public inbox for libabigail@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] CTF as a fallback when no DWARF debug info is present
@ 2022-10-01  0:15 Guillermo E. Martinez
  2022-10-04  9:04 ` Dodji Seketeli
  2022-11-15 20:13 ` [PATCHv2] ELF based front-end readers fallback feature Guillermo E. Martinez
  0 siblings, 2 replies; 17+ messages in thread
From: Guillermo E. Martinez @ 2022-10-01  0:15 UTC (permalink / raw)
  To: libabigail; +Cc: Guillermo E. Martinez

Hello,

This patch implements the CTF fallback behaviour in libabigail tools
when DWARF debug info is not present.

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 binaries 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 which of them were added or removed.

In case of neither DWARF nor CTF debug information is present
(`STATUS_DEBUG_INFO_NOT_FOUND') and `--ctf' option was not passed in
the command line, those tools use the symbol object build by DWARF
reader (default) to completed  theirs task.

Tools don't allow comparing corpora built with between different debug
information i.e DWARF vs CTF, the first corpus built dictate the
expected debug information in the second one.

This work for libraries and Linux kernel.  The `--ctf' option is
preserved to explicitly indicate to those tools that we want to use
CTF support.

	* 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.
	* src/abg-ctf-reader.cc (slurp_elf_info): Report status
	when debug information is not present.
	(read_corpus): Add code to locate `vmlinux.ctfa' just when
	`main corpus' is being processed.
	* src/abg-tools-utils.cc (maybe_load_vmlinux_dwarf_corpus):
	Replace by a reference `origin' argument to notify whether
	CTF reader needs to be executed.
	* tests/data/test-diff-pkg-ctf/dirpkg-3-report-2.txt: Adjust
	test case.
	* tests/test-diff-pkg.cc (in_out_specs): Add `--ctf' option
	in test case.
	* tools/abidiff.cc (main): Add `origin' depending of command
	line argument by default it is `corpus::DWARF_ORIGIN'. Add
	`dwarf_corpus' to be used as default corpus (containing ELF
	symbols), when DWARF nor CTF debug information was found.
	* 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 +-
 src/abg-ctf-reader.cc                         |  33 +++--
 src/abg-tools-utils.cc                        |  22 +++-
 .../test-diff-pkg-ctf/dirpkg-3-report-2.txt   |  16 +++
 tests/test-diff-pkg.cc                        |   2 +-
 tools/abidiff.cc                              |  82 ++++++++-----
 tools/abidw.cc                                |  54 +++++---
 tools/abipkgdiff.cc                           | 116 +++++++++++-------
 11 files changed, 257 insertions(+), 120 deletions(-)

diff --git a/doc/manuals/abidiff.rst b/doc/manuals/abidiff.rst
index 0c711d9e..caeceded 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
 
@@ -558,7 +559,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``
@@ -785,4 +786,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/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 9148a646..b3cde365 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -45,6 +45,7 @@ namespace ctf_reader
 using std::dynamic_pointer_cast;
 using abigail::tools_utils::dir_name;
 using abigail::tools_utils::file_exists;
+using abigail::tools_utils::base_name;
 
 class read_context
 {
@@ -1545,7 +1546,12 @@ slurp_elf_info(read_context *ctxt,
   corp->set_architecture_name(elf_helpers::e_machine_to_string(ehdr->e_machine));
 
   find_alt_debuginfo(ctxt, &ctf_dbg_scn);
-  ABG_ASSERT(ctxt->symtab);
+  if (!ctxt->symtab)
+    {
+      status |= elf_reader::STATUS_NO_SYMBOLS_FOUND;
+      return;
+    }
+
   corp->set_symtab(ctxt->symtab);
 
   if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
@@ -1564,7 +1570,8 @@ slurp_elf_info(read_context *ctxt,
         ctf_scn = ctf_dbg_scn;
       else
         {
-          status |= elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
+          status |= (elf_reader::STATUS_OK |
+                     elf_reader::STATUS_DEBUG_INFO_NOT_FOUND);
           return;
         }
     }
@@ -1676,15 +1683,15 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
     origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
   corp->set_origin(origin);
 
-  if (ctxt->cur_corpus_group_)
-    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
-
   slurp_elf_info(ctxt, corp, status);
-  if (!is_linux_kernel
-      && ((status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND) |
-          (status & elf_reader::STATUS_NO_SYMBOLS_FOUND)))
+  if ((status & elf_reader::STATUS_NO_SYMBOLS_FOUND) ||
+      (!is_linux_kernel &&
+       (status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)))
       return corp;
 
+  if (ctxt->cur_corpus_group_)
+    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
+
   // Set the set of exported declaration that are defined.
   ctxt->exported_decls_builder
    (ctxt->cur_corpus_->get_exported_decls_builder().get());
@@ -1695,9 +1702,13 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
     {
       if (ctxt->ctfa == NULL)
         {
-          std::string ctfa_filename;
-          if (find_ctfa_file(ctxt, ctfa_filename))
-            ctxt->ctfa = ctf_arc_open(ctfa_filename.c_str(), &errp);
+          std::string filename;
+          base_name(ctxt->filename, filename);
+
+          // locate vmlinux.ctfa only when reader is processing
+          // vmlinux file, i.e the main corpus in the group.
+          if (filename == "vmlinux" && find_ctfa_file(ctxt, filename))
+            ctxt->ctfa = ctf_arc_open(filename.c_str(), &errp);
         }
     }
   else
diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
index fe9ebc72..7d00f726 100644
--- a/src/abg-tools-utils.cc
+++ b/src/abg-tools-utils.cc
@@ -2493,6 +2493,11 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
 /// made of vmlinux kernel file and the linux kernel modules found
 /// under @p root directory and under its sub-directories, recursively.
 ///
+/// If the vmlinux file doens't have DWARF info, it looks for
+/// vmlinux.ctfa, if it's present, it assumes that kernel was build
+/// with CTF support, then it updates @ref origin, given chance to
+/// CTF reader to build the IR for kernel build directory.
+///
 /// @param origin the debug type information in vmlinux kernel and
 /// the linux kernel modules to be used to build the corpora @p group.
 ///
@@ -2526,7 +2531,7 @@ 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,
+maybe_load_vmlinux_dwarf_corpus(corpus::origin      &origin,
                                 corpus_group_sptr&  group,
                                 const string&       vmlinux,
                                 vector<string>&     modules,
@@ -2578,6 +2583,21 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
      << " reading DONE:"
      << t << "\n";
 
+  if (status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
+    {
+      // vmlinux doesn't have DWARF debug info, so it might contain
+      // CTF debug info, this means vmlinux.ctfa is under kernel
+      // build directory.
+      string ctfa_file = root + "/vmlinux.ctfa";
+      if (file_exists(ctfa_file))
+        {
+          // OK. Likely CTF could build a better IR, then let's
+          // notify the caller to try with CTF reader.
+          origin = corpus::CTF_ORIGIN;
+          return;
+        }
+    }
+
   if (group->is_empty())
     return;
 
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/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/tools/abidiff.cc b/tools/abidiff.cc
index e0bb35ac..815c68df 100644
--- a/tools/abidiff.cc
+++ b/tools/abidiff.cc
@@ -1118,6 +1118,13 @@ main(int argc, char* argv[])
       return 0;
     }
 
+  corpus::origin first_input_origin;
+  corpus::origin origin =
+#ifdef WITH_CTF
+    opts.use_ctf ? corpus::CTF_ORIGIN :
+#endif
+    corpus::DWARF_ORIGIN;
+
   prepare_di_root_paths(opts);
 
   if (!maybe_check_suppression_files(opts))
@@ -1150,7 +1157,7 @@ main(int argc, char* argv[])
       abigail::elf_reader::status c1_status =
 	abigail::elf_reader::STATUS_OK,
 	c2_status = abigail::elf_reader::STATUS_OK;
-      corpus_sptr c1, c2;
+      corpus_sptr c1, c2, dwarf_corpus;
       corpus_group_sptr g1, g2;
       bool files_suppressed = false;
 
@@ -1180,20 +1187,9 @@ main(int argc, char* argv[])
 	case abigail::tools_utils::FILE_TYPE_ELF: // fall through
 	case abigail::tools_utils::FILE_TYPE_AR:
 	  {
-#ifdef WITH_CTF
-            if (opts.use_ctf)
-              {
-                abigail::ctf_reader::read_context_sptr ctxt
-                  = abigail::ctf_reader::create_read_context(opts.file1,
-                                                             opts.prepared_di_root_paths1,
-                                                             env.get());
-                ABG_ASSERT(ctxt);
-                c1 = abigail::ctf_reader::read_corpus(ctxt.get(),
-                                                      c1_status);
-              }
-            else
-#endif
+            if (origin & corpus::DWARF_ORIGIN)
               {
+                first_input_origin = corpus::DWARF_ORIGIN;
                 abigail::dwarf_reader::read_context_sptr ctxt =
                   abigail::dwarf_reader::create_read_context
                   (opts.file1, opts.prepared_di_root_paths1,
@@ -1205,6 +1201,7 @@ main(int argc, char* argv[])
                 set_suppressions(*ctxt, opts);
                 abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
                 c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
+                dwarf_corpus = c1;
                 if (!c1
                     || (opts.fail_no_debug_info
                         && (c1_status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
@@ -1212,7 +1209,31 @@ main(int argc, char* argv[])
                   return handle_error(c1_status, ctxt.get(),
                                       argv[0], opts);
               }
-	  }
+#ifdef WITH_CTF
+            if (((c1_status & STATUS_OK) &&
+                 (c1_status & STATUS_DEBUG_INFO_NOT_FOUND)) ||
+                (origin & corpus::CTF_ORIGIN))
+              {
+                first_input_origin = corpus::CTF_ORIGIN;
+                abigail::ctf_reader::read_context_sptr ctxt
+                  = abigail::ctf_reader::create_read_context(opts.file1,
+                                                             opts.prepared_di_root_paths1,
+                                                             env.get());
+                ABG_ASSERT(ctxt);
+                c1 = abigail::ctf_reader::read_corpus(ctxt.get(),
+                                                      c1_status);
+                // If CTF was not explicitly selected in the command line and
+                // there is no CTF information, then compare DWARF corpora
+                // by default only with symbols information.
+                if ((origin & corpus::DWARF_ORIGIN) &&
+                    (c1_status & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND))
+                  {
+                    first_input_origin = corpus::DWARF_ORIGIN;
+                    c1 = dwarf_corpus;
+                  }
+              }
+#endif
+          }
 	  break;
 	case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
 	  {
@@ -1264,19 +1285,7 @@ main(int argc, char* argv[])
 	case abigail::tools_utils::FILE_TYPE_ELF: // Fall through
 	case abigail::tools_utils::FILE_TYPE_AR:
 	  {
-#ifdef WITH_CTF
-            if (opts.use_ctf)
-              {
-                abigail::ctf_reader::read_context_sptr ctxt
-                  = abigail::ctf_reader::create_read_context(opts.file2,
-                                                             opts.prepared_di_root_paths2,
-                                                             env.get());
-                ABG_ASSERT(ctxt);
-                c2 = abigail::ctf_reader::read_corpus(ctxt.get(),
-                                                      c2_status);
-              }
-            else
-#endif
+            if (first_input_origin & corpus::DWARF_ORIGIN)
               {
                 abigail::dwarf_reader::read_context_sptr ctxt =
                   abigail::dwarf_reader::create_read_context
@@ -1295,7 +1304,19 @@ main(int argc, char* argv[])
                         && (c2_status & STATUS_DEBUG_INFO_NOT_FOUND)))
                   return handle_error(c2_status, ctxt.get(), argv[0], opts);
               }
-	  }
+#ifdef WITH_CTF
+            else
+              {
+                abigail::ctf_reader::read_context_sptr ctxt
+                  = abigail::ctf_reader::create_read_context(opts.file2,
+                                                             opts.prepared_di_root_paths2,
+                                                             env.get());
+                ABG_ASSERT(ctxt);
+                c2 = abigail::ctf_reader::read_corpus(ctxt.get(),
+                                                      c2_status);
+              }
+#endif
+          }
 	  break;
 	case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
 	  {
@@ -1334,7 +1355,8 @@ main(int argc, char* argv[])
 
       if (!!c1 != !!c2
 	  || !!t1 != !!t2
-	  || !!g1 != !!g2)
+	  || !!g1 != !!g2
+          || c1_status != c2_status)
 	{
 	  emit_prefix(argv[0], cerr)
 	    << "the two input should be of the same kind\n";
diff --git a/tools/abidw.cc b/tools/abidw.cc
index f38d6048..9b03069b 100644
--- a/tools/abidw.cc
+++ b/tools/abidw.cc
@@ -551,25 +551,15 @@ load_corpus_and_write_abixml(char* argv[],
 
   // First of all, read a libabigail IR corpus from the file specified
   // in OPTS.
-  corpus_sptr corp;
+  corpus_sptr corp, dwarf_corpus;
   elf_reader::status s = elf_reader::STATUS_UNKNOWN;
+  corpus::origin origin =
 #ifdef WITH_CTF
-  if (opts.use_ctf)
-    {
-      abigail::ctf_reader::read_context_sptr ctxt
-        = abigail::ctf_reader::create_read_context(opts.in_file_path,
-                                                   opts.prepared_di_root_paths,
-                                                   env.get());
-      assert (ctxt);
-      t.start();
-      corp = abigail::ctf_reader::read_corpus (ctxt, s);
-      t.stop();
-      if (opts.do_log)
-        emit_prefix(argv[0], cerr)
-          << "read corpus from elf file in: " << t << "\n";
-    }
-  else
+    opts.use_ctf ? corpus::CTF_ORIGIN :
 #endif
+    corpus::DWARF_ORIGIN;
+
+  if (origin & corpus::DWARF_ORIGIN)
     {
       dwarf_reader::read_context_sptr c
         = abigail::dwarf_reader::create_read_context(opts.in_file_path,
@@ -616,7 +606,7 @@ load_corpus_and_write_abixml(char* argv[],
         }
 
       if (opts.exported_interfaces_only.has_value())
-	env->analyze_exported_interfaces_only(*opts.exported_interfaces_only);
+        env->analyze_exported_interfaces_only(*opts.exported_interfaces_only);
 
       t.start();
       corp = dwarf_reader::read_corpus_from_elf(ctxt, s);
@@ -632,7 +622,35 @@ load_corpus_and_write_abixml(char* argv[],
       if (opts.do_log)
         emit_prefix(argv[0], cerr)
           << "reset read context in: " << t << "\n";
+
+      dwarf_corpus = corp;
     }
+#ifdef WITH_CTF
+  if (((s & abigail::elf_reader::STATUS_OK) &&
+       (s & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)) ||
+      (origin & corpus::CTF_ORIGIN))
+    {
+      abigail::ctf_reader::read_context_sptr ctxt
+        = abigail::ctf_reader::create_read_context(opts.in_file_path,
+                                                   opts.prepared_di_root_paths,
+                                                   env.get());
+      assert (ctxt);
+      t.start();
+      corp = abigail::ctf_reader::read_corpus (ctxt, s);
+      t.stop();
+
+      // If CTF was not explicitly selected in the command line and
+      // there is no CTF information, then compare DWARF corpora
+      // by default only with symbols information.
+      if ((origin & corpus::DWARF_ORIGIN) &&
+          (s & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND))
+        corp = dwarf_corpus;
+
+      if (opts.do_log)
+        emit_prefix(argv[0], cerr)
+          << "read corpus from elf file in: " << t << "\n";
+    }
+#endif
 
   // If we couldn't create a corpus, emit some (hopefully) useful
   // diagnostics and return and error.
@@ -834,7 +852,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 656d5882..7704ac72 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::corpus;
 using abigail::ir::corpus_sptr;
 using abigail::ir::corpus_group_sptr;
 using abigail::comparison::diff_context;
@@ -1320,33 +1321,54 @@ compare(const elf_file& elf1,
       << elf1.path
       << " ...\n";
 
-  corpus_sptr corpus1;
+  corpus_sptr corpus1, dwarf_corpus;
+  corpus::origin first_input_origin;
+  corpus::origin origin =
+#ifdef WITH_CTF
+    opts.use_ctf ? corpus::CTF_ORIGIN :
+#endif
+    corpus::DWARF_ORIGIN;
+
 #ifdef WITH_CTF
   abigail::ctf_reader::read_context_sptr ctxt_ctf;
 #endif
   read_context_sptr ctxt_dwarf;
   {
+    if (origin & corpus::DWARF_ORIGIN)
+      {
+        first_input_origin = corpus::DWARF_ORIGIN;
+        ctxt_dwarf = create_read_context(elf1.path, di_dirs1, env.get(),
+                                         /*load_all_types=*/opts.show_all_types);
+        add_read_context_suppressions(*ctxt_dwarf, priv_types_supprs1);
+        if (!opts.kabi_suppressions.empty())
+          add_read_context_suppressions(*ctxt_dwarf, opts.kabi_suppressions);
+
+        corpus1 = read_corpus_from_elf(*ctxt_dwarf, c1_status);
+        dwarf_corpus = corpus1;
+      }
 #ifdef WITH_CTF
-    if (opts.use_ctf)
+    if (((c1_status & abigail::elf_reader::STATUS_OK) &&
+         (c1_status & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)) ||
+        (origin & corpus::CTF_ORIGIN))
       {
+        first_input_origin = corpus::CTF_ORIGIN;
         ctxt_ctf = abigail::ctf_reader::create_read_context(elf1.path,
 							    di_dirs1,
                                                             env.get());
         ABG_ASSERT(ctxt_ctf);
         corpus1 = abigail::ctf_reader::read_corpus(ctxt_ctf.get(),
                                                    c1_status);
+        // If CTF was not explicitly selected in the command line and
+        // there is no CTF information, then compare DWARF corpora
+        // by default only with symbols information.
+        if ((origin & corpus::DWARF_ORIGIN) &&
+            (c1_status & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND))
+          {
+            first_input_origin = corpus::DWARF_ORIGIN;
+            corpus1 = dwarf_corpus;
+          }
       }
-    else
 #endif
-      {
-        ctxt_dwarf = create_read_context(elf1.path, di_dirs1, env.get(),
-                                         /*load_all_types=*/opts.show_all_types);
-        add_read_context_suppressions(*ctxt_dwarf, priv_types_supprs1);
-        if (!opts.kabi_suppressions.empty())
-          add_read_context_suppressions(*ctxt_dwarf, opts.kabi_suppressions);
-
-        corpus1 = read_corpus_from_elf(*ctxt_dwarf, c1_status);
-      }
 
     bool bail_out = false;
     if (!(c1_status & abigail::elf_reader::STATUS_OK))
@@ -1392,11 +1414,7 @@ compare(const elf_file& elf1,
 	    emit_prefix("abipkgdiff", cerr)
 	      << "Could not find alternate debug info file";
 	    string alt_di_path;
-#ifdef WITH_CTF
-            if (opts.use_ctf)
-              ;
-            else
-#endif
+            if (first_input_origin & corpus::DWARF_ORIGIN)
               abigail::dwarf_reader::refers_to_alt_debug_info(*ctxt_dwarf,
                                                               alt_di_path);
 	    if (!alt_di_path.empty())
@@ -1431,17 +1449,7 @@ compare(const elf_file& elf1,
 
   corpus_sptr corpus2;
   {
-#ifdef WITH_CTF
-    if (opts.use_ctf)
-      {
-        ctxt_ctf = abigail::ctf_reader::create_read_context(elf2.path,
-							    di_dirs2,
-							    env.get());
-        corpus2 = abigail::ctf_reader::read_corpus(ctxt_ctf.get(),
-                                                   c2_status);
-      }
-    else
-#endif
+    if (first_input_origin & corpus::DWARF_ORIGIN)
       {
         ctxt_dwarf = create_read_context(elf2.path, di_dirs2, env.get(),
                                          /*load_all_types=*/opts.show_all_types);
@@ -1452,6 +1460,16 @@ compare(const elf_file& elf1,
 
         corpus2 = read_corpus_from_elf(*ctxt_dwarf, c2_status);
       }
+#ifdef WITH_CTF
+    else
+      {
+        ctxt_ctf = abigail::ctf_reader::create_read_context(elf2.path,
+							    di_dirs2,
+							    env.get());
+        corpus2 = abigail::ctf_reader::read_corpus(ctxt_ctf.get(),
+                                                   c2_status);
+      }
+#endif
 
     bool bail_out = false;
     if (!(c2_status & abigail::elf_reader::STATUS_OK))
@@ -1497,11 +1515,8 @@ compare(const elf_file& elf1,
 	    emit_prefix("abipkgdiff", cerr)
 	      << "Could not find alternate debug info file";
 	    string alt_di_path;
-#ifdef WITH_CTF
-            if (opts.use_ctf)
-              ;
-            else
-#endif
+
+            if (first_input_origin & corpus::DWARF_ORIGIN)
               abigail::dwarf_reader::refers_to_alt_debug_info(*ctxt_dwarf,
                                                               alt_di_path);
 	    if (!alt_di_path.empty())
@@ -1599,14 +1614,31 @@ compare_to_self(const elf_file& elf,
       << elf.path
       << " ...\n";
 
-  corpus_sptr corp;
+  corpus_sptr corp, dwarf_corpus;
+  corpus::origin origin =
+#ifdef WITH_CTF
+    opts.use_ctf ? corpus::CTF_ORIGIN :
+#endif
+    corpus::DWARF_ORIGIN;
 #ifdef WITH_CTF
   abigail::ctf_reader::read_context_sptr ctxt_ctf;
 #endif
+
   read_context_sptr ctxt_dwarf;
   {
+    if (origin & corpus::DWARF_ORIGIN)
+      {
+        ctxt_dwarf =
+         create_read_context(elf.path, di_dirs, env.get(),
+                             /*read_all_types=*/opts.show_all_types);
+
+        corp = read_corpus_from_elf(*ctxt_dwarf, c_status);
+        dwarf_corpus = corp;
+      }
 #ifdef WITH_CTF
-    if (opts.use_ctf)
+    if (((c_status & abigail::elf_reader::STATUS_OK) &&
+         (c_status & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)) ||
+        (origin & corpus::CTF_ORIGIN))
       {
         ctxt_ctf = abigail::ctf_reader::create_read_context(elf.path,
 							    di_dirs,
@@ -1614,16 +1646,14 @@ compare_to_self(const elf_file& elf,
         ABG_ASSERT(ctxt_ctf);
         corp = abigail::ctf_reader::read_corpus(ctxt_ctf.get(),
                                                    c_status);
+        // If CTF was not explicitly selected in the command line and
+        // there is no CTF information, then use DWARF corpus
+        // by default just with symbols information.
+        if ((origin & corpus::DWARF_ORIGIN) &&
+            (c_status & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND))
+          corp = dwarf_corpus;
       }
-    else
 #endif
-      {
-        ctxt_dwarf =
-         create_read_context(elf.path, di_dirs, env.get(),
-                             /*read_all_types=*/opts.show_all_types);
-
-        corp = read_corpus_from_elf(*ctxt_dwarf, c_status);
-      }
 
     if (!(c_status & abigail::elf_reader::STATUS_OK))
       {
-- 
2.35.1


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

* Re: [PATCH] CTF as a fallback when no DWARF debug info is present
  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-11-15 20:13 ` [PATCHv2] ELF based front-end readers fallback feature Guillermo E. Martinez
  1 sibling, 1 reply; 17+ messages in thread
From: Dodji Seketeli @ 2022-10-04  9:04 UTC (permalink / raw)
  To: Guillermo E. Martinez via Libabigail; +Cc: Guillermo E. Martinez

Hello Guillermo,

Thank you for this patch.

Please find my comments below.

"Guillermo E. Martinez via Libabigail" <libabigail@sourceware.org> a
écrit:


> 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 binaries 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 which of them were added or removed.
>
> In case of neither DWARF nor CTF debug information is present
> (`STATUS_DEBUG_INFO_NOT_FOUND') and `--ctf' option was not passed in
> the command line, those tools use the symbol object build by DWARF
> reader (default) to completed  theirs task.
>
> Tools don't allow comparing corpora built with between different debug
> information i.e DWARF vs CTF, the first corpus built dictate the
> expected debug information in the second one.
>
> This work for libraries and Linux kernel.  The `--ctf' option is
> preserved to explicitly indicate to those tools that we want to use
> CTF support.
>
> 	* 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.

I have made some slight fixes to changes to these doc files.  Nothing
major you'll see the changes in the updated version of the patch that I
am posting at the end of this message.

[...]

> 	* src/abg-ctf-reader.cc (slurp_elf_info): Report status
> 	when debug information is not present.
> 	(read_corpus): Add code to locate `vmlinux.ctfa' just when
> 	`main corpus' is being processed.
> 	* src/abg-tools-utils.cc (maybe_load_vmlinux_dwarf_corpus):
> 	Replace by a reference `origin' argument to notify whether
> 	CTF reader needs to be executed.
> 	* tests/data/test-diff-pkg-ctf/dirpkg-3-report-2.txt: Adjust
> 	test case.
> 	* tests/test-diff-pkg.cc (in_out_specs): Add `--ctf' option
> 	in test case.
> 	* tools/abidiff.cc (main): Add `origin' depending of command
> 	line argument by default it is `corpus::DWARF_ORIGIN'. Add
> 	`dwarf_corpus' to be used as default corpus (containing ELF
> 	symbols), when DWARF nor CTF debug information was found.
> 	* 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 +-
>  src/abg-ctf-reader.cc                         |  33 +++--
>  src/abg-tools-utils.cc                        |  22 +++-
>  .../test-diff-pkg-ctf/dirpkg-3-report-2.txt   |  16 +++
>  tests/test-diff-pkg.cc                        |   2 +-
>  tools/abidiff.cc                              |  82 ++++++++-----
>  tools/abidw.cc                                |  54 +++++---
>  tools/abipkgdiff.cc                           | 116 +++++++++++-------
>  11 files changed, 257 insertions(+), 120 deletions(-)
>
> diff --git a/doc/manuals/abidiff.rst b/doc/manuals/abidiff.rst
> index 0c711d9e..caeceded 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
>  
> @@ -558,7 +559,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``
> @@ -785,4 +786,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/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
> index 9148a646..b3cde365 100644
> --- a/src/abg-ctf-reader.cc
> +++ b/src/abg-ctf-reader.cc
> @@ -45,6 +45,7 @@ namespace ctf_reader
>  using std::dynamic_pointer_cast;
>  using abigail::tools_utils::dir_name;
>  using abigail::tools_utils::file_exists;
> +using abigail::tools_utils::base_name;
>  
>  class read_context
>  {
> @@ -1545,7 +1546,12 @@ slurp_elf_info(read_context *ctxt,
>    corp->set_architecture_name(elf_helpers::e_machine_to_string(ehdr->e_machine));
>  
>    find_alt_debuginfo(ctxt, &ctf_dbg_scn);
> -  ABG_ASSERT(ctxt->symtab);
> +  if (!ctxt->symtab)
> +    {
> +      status |= elf_reader::STATUS_NO_SYMBOLS_FOUND;
> +      return;
> +    }
> +
>    corp->set_symtab(ctxt->symtab);
>  
>    if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
> @@ -1564,7 +1570,8 @@ slurp_elf_info(read_context *ctxt,
>          ctf_scn = ctf_dbg_scn;
>        else
>          {
> -          status |= elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
> +          status |= (elf_reader::STATUS_OK |
> +                     elf_reader::STATUS_DEBUG_INFO_NOT_FOUND);
>            return;
>          }
>      }
> @@ -1676,15 +1683,15 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
>      origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
>    corp->set_origin(origin);
>  
> -  if (ctxt->cur_corpus_group_)
> -    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
> -
>    slurp_elf_info(ctxt, corp, status);
> -  if (!is_linux_kernel
> -      && ((status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND) |
> -          (status & elf_reader::STATUS_NO_SYMBOLS_FOUND)))
> +  if ((status & elf_reader::STATUS_NO_SYMBOLS_FOUND) ||
> +      (!is_linux_kernel &&
> +       (status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)))
>        return corp;
>  
> +  if (ctxt->cur_corpus_group_)
> +    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
> +
>    // Set the set of exported declaration that are defined.
>    ctxt->exported_decls_builder
>     (ctxt->cur_corpus_->get_exported_decls_builder().get());
> @@ -1695,9 +1702,13 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
>      {
>        if (ctxt->ctfa == NULL)
>          {
> -          std::string ctfa_filename;
> -          if (find_ctfa_file(ctxt, ctfa_filename))
> -            ctxt->ctfa = ctf_arc_open(ctfa_filename.c_str(), &errp);
> +          std::string filename;
> +          base_name(ctxt->filename, filename);
> +
> +          // locate vmlinux.ctfa only when reader is processing
> +          // vmlinux file, i.e the main corpus in the group.
> +          if (filename == "vmlinux" && find_ctfa_file(ctxt, filename))
> +            ctxt->ctfa = ctf_arc_open(filename.c_str(), &errp);
>          }
>      }
>    else
> diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
> index fe9ebc72..7d00f726 100644
> --- a/src/abg-tools-utils.cc
> +++ b/src/abg-tools-utils.cc
> @@ -2493,6 +2493,11 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
>  /// made of vmlinux kernel file and the linux kernel modules found
>  /// under @p root directory and under its sub-directories, recursively.
>  ///
> +/// If the vmlinux file doens't have DWARF info, it looks for
> +/// vmlinux.ctfa, if it's present, it assumes that kernel was build
> +/// with CTF support, then it updates @ref origin, given chance to
> +/// CTF reader to build the IR for kernel build directory.
> +///
>  /// @param origin the debug type information in vmlinux kernel and
>  /// the linux kernel modules to be used to build the corpora @p group.
>  ///
> @@ -2526,7 +2531,7 @@ 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,
> +maybe_load_vmlinux_dwarf_corpus(corpus::origin      &origin,
>                                  corpus_group_sptr&  group,
>                                  const string&       vmlinux,
>                                  vector<string>&     modules,
> @@ -2578,6 +2583,21 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>       << " reading DONE:"
>       << t << "\n";
>  
> +  if (status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
> +    {
> +      // vmlinux doesn't have DWARF debug info, so it might contain
> +      // CTF debug info, this means vmlinux.ctfa is under kernel
> +      // build directory.
> +      string ctfa_file = root + "/vmlinux.ctfa";
> +      if (file_exists(ctfa_file))
> +        {
> +          // OK. Likely CTF could build a better IR, then let's
> +          // notify the caller to try with CTF reader.
> +          origin = corpus::CTF_ORIGIN;
> +          return;
> +        }
> +    }
> +

Hmmh, I think this change is done at logical level that is too "low",
compared to the level at which I believe this decision should be made.
Namely, maybe_load_vmlinux_dwarf_corpus is meant to try to load DWARF
debug information.  It should not deal with CTF debug information
(looking for CTF archive files etc).  Rather, I think that if the
loading of DWARF failed, that function should tell its caller about it.
It would thus be up to the caller to decide what to do with that
information. For instance, the caller would then be able to try and load
CTF debug information instead.

So I would rather modify maybe_load_vmlinux_dwarf_corpus to make it
return the status of the loading, so that the caller can know if the
loading succeeded or not.

So here is the change I would propose for the
maybe_load_vmlinux_dwarf_corpus and maybe_load_vmlinux_ctf_corpus
functions instead (it's part of the whole patch that I have posted at
the end of this message):

    @@ -2525,8 +2542,12 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
     /// @param t time to trace time spent in each step.
     ///
     /// @param env the environment to create the corpus_group in.
    -static void
    -maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
    +///
    +/// @return the status of the loading.  If it's
    +/// abigail::elf_reader::STATUS_UNKNOWN, then it means nothing was
    +/// done, meaning the function got out early.
    +static abigail::elf_reader::status
    +maybe_load_vmlinux_dwarf_corpus(corpus::origin&     origin,
                                     corpus_group_sptr&  group,
                                     const string&       vmlinux,
                                     vector<string>&     modules,
    @@ -2539,10 +2560,11 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
                                     timer&              t,
                                     environment_sptr&   env)
     {
    +  abigail::elf_reader::status status = abigail::elf_reader::STATUS_UNKNOWN;
    +
       if (!(origin & corpus::DWARF_ORIGIN))
    -    return;
    +    return status;

    -  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
       dwarf_reader::read_context_sptr ctxt;
       ctxt =
        dwarf_reader::create_read_context(vmlinux, di_roots, env.get(),
    @@ -2569,6 +2591,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
          << vmlinux << "' ...\n" << std::flush;

       // Read the vmlinux corpus and add it to the group.
    +  status = abigail::elf_reader::STATUS_OK;
       t.start();
       read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
       t.stop();
    @@ -2579,7 +2602,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
          << t << "\n";

       if (group->is_empty())
    -    return;
    +    return status;

       // Now add the corpora of the modules to the corpus group.
       int total_nb_modules = modules.size();
    @@ -2614,6 +2637,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
              << "' reading DONE: "
              << t << "\n";
         }
    +  return status;
     }

     /// If the @ref origin is CTF_ORIGIN it build a @ref corpus_group
    @@ -2642,8 +2666,12 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
     /// @param t time to trace time spent in each step.
     ///
     /// @param env the environment to create the corpus_group in.
    +///
    +/// @return the status of the loading.  If it's
    +/// abigail::elf_reader::STATUS_UNKNOWN, then it means nothing was
    +/// done, meaning the function got out early.
     #ifdef WITH_CTF
    -static void
    +static abigail::elf_reader::status
     maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
                                   corpus_group_sptr&  group,
                                   const string&       vmlinux,
    @@ -2654,10 +2682,11 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
                                   timer&              t,
                                   environment_sptr&   env)
     {
    +  abigail::elf_reader::status status = abigail::elf_reader::STATUS_UNKNOWN;
    +
       if (!(origin & corpus::CTF_ORIGIN))
    -    return;
    +    return status;

    -  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
       ctf_reader::read_context_sptr ctxt;
       ctxt = ctf_reader::create_read_context(vmlinux, di_roots, env.get());
       group.reset(new corpus_group(env.get(), root));
    @@ -2668,6 +2697,7 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
          << vmlinux << "' ...\n" << std::flush;

       // Read the vmlinux corpus and add it to the group.
    +  status = abigail::elf_reader::STATUS_OK;
       t.start();
       read_and_add_corpus_to_group_from_elf(ctxt.get(), *group, status);
       t.stop();
    @@ -2678,7 +2708,7 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
          << t << "\n";

       if (group->is_empty())
    -    return;
    +    return status;

       // Now add the corpora of the modules to the corpus group.
       int total_nb_modules = modules.size();
    @@ -2707,6 +2737,7 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
              << "' reading DONE: "
              << t << "\n";
         }
    +  return status;
     }
     #endif

I have also introduced a new function called
tools_utils::dir_contains_ctf_archive to look for a file that ends with
".ctfa".  This abstracts away the search for "vmlinux.ctfa" as I wasn't
sure if those archives could exist for normal (non-kernel) binaries as
well:

    diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
    index fe9ebc72..a23f08ea 100644
    --- a/src/abg-tools-utils.cc
    +++ b/src/abg-tools-utils.cc
    @@ -1694,6 +1694,23 @@ file_is_kernel_debuginfo_package(const string& file_name, file_type file_type)
       return result;
     }

    +/// 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;
    +}
    +

Then, now that the caller of these functions can know if loading the
vmlinux binary succeeded or not, we can update that caller, which is
build_corpus_group_from_kernel_dist_under:

    @@ -2786,14 +2817,23 @@ 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_reader::status status =
    +	maybe_load_vmlinux_dwarf_corpus(origin, group, vmlinux,
    +					modules, root, di_roots,
    +					suppr_paths, kabi_wl_paths,
    +					supprs, verbose, t, env);
     #ifdef WITH_CTF
    +      string vmlinux_basename;
    +      base_name(vmlinux, vmlinux_basename);
    +      if (origin == corpus::DWARF_ORIGIN
    +	  && (status & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
    +	  && dir_contains_ctf_archive(root, vmlinux_basename))
    +	  // Let's try to load the binary using the CTF archive!
    +	origin |= corpus::CTF_ORIGIN;
    +
           maybe_load_vmlinux_ctf_corpus(origin, group, vmlinux,
    -                                    modules, root, di_roots,
    -                                    verbose, t, env);
    +				    modules, root, di_roots,
    +				    verbose, t, env);
     #endif
         }

If you feel like we shouldn't test if the directory 'root' contains a
ctf archive before trying to load the CTF archive, then please remove
the call to dir_contains_ctf_archive above.  I just meant to show the
general idea of where the decision should be made to try to load the ctf
debug information, in my opinion.

The general idea, however, is to make the reader of
build_corpus_group_from_kernel_dist_under understand what is going on
(that is, we try loading vmlinux with DWARF, and if it fails, then we
try CTF) without having to go dig deep into how
maybe_load_vmlinux_ctf_corpus works.

Similarly, I amended the changes to the tools (abi{diff,dw,pkgdiff}) to
make them follow the same path.

[...]

> diff --git a/tools/abidiff.cc b/tools/abidiff.cc
> index e0bb35ac..815c68df 100644
> --- a/tools/abidiff.cc
> +++ b/tools/abidiff.cc
> @@ -1118,6 +1118,13 @@ main(int argc, char* argv[])
>        return 0;
>      }
>  
> +  corpus::origin first_input_origin;
> +  corpus::origin origin =
> +#ifdef WITH_CTF
> +    opts.use_ctf ? corpus::CTF_ORIGIN :
> +#endif
> +    corpus::DWARF_ORIGIN;
> +

I removed these changes above.  This is because we don't need to perform
so many changes.  We can just let the code as it was and add new code to
just one place to test if loading DWARF failed.  If it failed then we
try to load CTF.

See below.

>    prepare_di_root_paths(opts);
>  
>    if (!maybe_check_suppression_files(opts))
> @@ -1150,7 +1157,7 @@ main(int argc, char* argv[])
>        abigail::elf_reader::status c1_status =
>  	abigail::elf_reader::STATUS_OK,
>  	c2_status = abigail::elf_reader::STATUS_OK;
> -      corpus_sptr c1, c2;
> +      corpus_sptr c1, c2, dwarf_corpus;

Likewise, removed.

>        corpus_group_sptr g1, g2;
>        bool files_suppressed = false;
>  
> @@ -1180,20 +1187,9 @@ main(int argc, char* argv[])
>  	case abigail::tools_utils::FILE_TYPE_ELF: // fall through
>  	case abigail::tools_utils::FILE_TYPE_AR:
>  	  {
> -#ifdef WITH_CTF
> -            if (opts.use_ctf)
> -              {
> -                abigail::ctf_reader::read_context_sptr ctxt
> -                  = abigail::ctf_reader::create_read_context(opts.file1,
> -                                                             opts.prepared_di_root_paths1,
> -                                                             env.get());
> -                ABG_ASSERT(ctxt);
> -                c1 = abigail::ctf_reader::read_corpus(ctxt.get(),
> -                                                      c1_status);
> -              }
> -            else
> -#endif

I left this code in.  So no change here either.

> +            if (origin & corpus::DWARF_ORIGIN)
>                {
> +                first_input_origin = corpus::DWARF_ORIGIN;

I remove this change as well.  So, still no change.

>                  abigail::dwarf_reader::read_context_sptr ctxt =
>                    abigail::dwarf_reader::create_read_context
>                    (opts.file1, opts.prepared_di_root_paths1,
> @@ -1205,6 +1201,7 @@ main(int argc, char* argv[])
>                  set_suppressions(*ctxt, opts);
>                  abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
>                  c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
> +                dwarf_corpus = c1;

Likewise.

But then, it's here that we are going to inspect c1_status to see if
loading DWARF failed.  If it failed, then we'll try to load CTF.  So,
here is the change I am adding to the process of loading the corpus c1:


@@ -1205,6 +1208,36 @@ main(int argc, char* argv[])
                 set_suppressions(*ctxt, opts);
                 abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
                 c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
+
+#ifdef WITH_CTF
+		if (// We were not instructed to use CTF ...
+		    !opts.use_ctf
+		    // ... and yet, no debug info was found ...
+		    && (c1_status & STATUS_DEBUG_INFO_NOT_FOUND)
+		    // ... but we found ELF symbols ...
+		    && !(c1_status & STATUS_NO_SYMBOLS_FOUND))
+		  {
+		    string basenam, dirnam;
+		    base_name(opts.file1, basenam);
+		    dir_name(opts.file1, dirnam);
+		    // ... the input file seems to contain CTF
+		    // archive, so let's try to see if the file
+		    // contains a CTF archive, who knows ...
+		    if (dir_contains_ctf_archive(dirnam, basenam))
+		      {
+			// The file does contain CTF debug information finally!
+			abigail::ctf_reader::read_context_sptr ctxt =
+			  abigail::ctf_reader::create_read_context
+			  (opts.file1,
+			   opts.prepared_di_root_paths1,
+			   env.get());
+			ABG_ASSERT(ctxt);
+
+			c1 = abigail::ctf_reader::read_corpus(ctxt.get(),
+							      c1_status);
+		      }
+		  }
+#endif

OK, maybe the statement

    "if (dir_contains_ctf_archive(dirnam, basenam))"

above is not necessary as I am not sure if the CTF archive file is
supposed to be present for normal binaries or not.  If it's not
necessary, then please remove that line as well as the use of the
basenam/dirnam variables.

But you get the general idea.  We just test if loading DWARF failed
(even if we were not instructed to use CTF) and then we try to load CTF.
The change is at one place right after trying to load the DWARF,
logically.

I do something similar to the loading of the second corpus c2.


Here is the entire change to the abidiff file:

    diff --git a/tools/abidiff.cc b/tools/abidiff.cc
    index e0bb35ac..0d9e59c2 100644
    --- a/tools/abidiff.cc
    +++ b/tools/abidiff.cc
    @@ -47,6 +47,9 @@ using abigail::suppr::suppressions_type;
     using abigail::suppr::read_suppressions;
     using namespace abigail::dwarf_reader;
     using namespace abigail::elf_reader;
    +using abigail::tools_utils::base_name;
    +using abigail::tools_utils::dir_name;
    +using abigail::tools_utils::dir_contains_ctf_archive;
     using abigail::tools_utils::emit_prefix;
     using abigail::tools_utils::check_file;
     using abigail::tools_utils::guess_file_type;
    @@ -1205,6 +1208,36 @@ main(int argc, char* argv[])
                     set_suppressions(*ctxt, opts);
                     abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
                     c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
    +
    +#ifdef WITH_CTF
    +		if (// We were not instructed to use CTF ...
    +		    !opts.use_ctf
    +		    // ... and yet, no debug info was found ...
    +		    && (c1_status & STATUS_DEBUG_INFO_NOT_FOUND)
    +		    // ... but we found ELF symbols ...
    +		    && !(c1_status & STATUS_NO_SYMBOLS_FOUND))
    +		  {
    +		    string basenam, dirnam;
    +		    base_name(opts.file1, basenam);
    +		    dir_name(opts.file1, dirnam);
    +		    // ... the input file seems to contain CTF
    +		    // archive, so let's try to see if the file
    +		    // contains a CTF archive, who knows ...
    +		    if (dir_contains_ctf_archive(dirnam, basenam))
    +		      {
    +			// The file does contain CTF debug information finally!
    +			abigail::ctf_reader::read_context_sptr ctxt =
    +			  abigail::ctf_reader::create_read_context
    +			  (opts.file1,
    +			   opts.prepared_di_root_paths1,
    +			   env.get());
    +			ABG_ASSERT(ctxt);
    +
    +			c1 = abigail::ctf_reader::read_corpus(ctxt.get(),
    +							      c1_status);
    +		      }
    +		  }
    +#endif
                     if (!c1
                         || (opts.fail_no_debug_info
                             && (c1_status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
    @@ -1212,7 +1245,7 @@ main(int argc, char* argv[])
                       return handle_error(c1_status, ctxt.get(),
                                           argv[0], opts);
                   }
    -	  }
    +          }
              break;
            case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
              {
    @@ -1289,13 +1322,44 @@ main(int argc, char* argv[])
                     set_suppressions(*ctxt, opts);

                     c2 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c2_status);
    +
    +#ifdef WITH_CTF
    +		if (// We were not instructed to use CTF ...
    +		    !opts.use_ctf
    +		    // ... and yet, no debug info was found ...
    +		    && (c2_status & STATUS_DEBUG_INFO_NOT_FOUND)
    +		    // ... but we found ELF symbols ...
    +		    && !(c2_status & STATUS_NO_SYMBOLS_FOUND))
    +		  {
    +		    string basenam, dirnam;
    +		    base_name(opts.file2, basenam);
    +		    dir_name(opts.file2, dirnam);
    +		    // ... the input file seems to contain CTF
    +		    // archive, so let's try to see if the file
    +		    // contains a CTF archive, who knows ...
    +		      if (dir_contains_ctf_archive(dirnam, basenam))
    +		      {
    +			// The file does contain CTF debug information finally!
    +			abigail::ctf_reader::read_context_sptr ctxt =
    +			  abigail::ctf_reader::create_read_context
    +			  (opts.file2,
    +			   opts.prepared_di_root_paths2,
    +			   env.get());
    +			ABG_ASSERT(ctxt);
    +
    +			c2 = abigail::ctf_reader::read_corpus(ctxt.get(),
    +							      c2_status);
    +		      }
    +		  }
    +#endif
    +
                     if (!c2
                         || (opts.fail_no_debug_info
                             && (c2_status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
                             && (c2_status & STATUS_DEBUG_INFO_NOT_FOUND)))
                       return handle_error(c2_status, ctxt.get(), argv[0], opts);
                   }
    -	  }
    +          }
              break;
            case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
              {


By the way, I think there should be at least one test that exercises the
workflow "try to load DWARF from the binary, fail, try to load CTF,
succeed", without having the --ctf provided.  And we should have that
test for all the tools that were modified.  We don't need to have that
for a Linux Kernel, obviously, as that would be too big to have in the
tarball.

Below is the entire amended patch that I came up with.  I suspect the
use of the dir_contains_ctf_archive function everywhere is wrong, but
I'll let you be the judge of that.  I think the documentation of when
that archive is present/necessary would be good to improve/add.

Thanks again for the patch!


From 481b547d7871a544b690943b16e6a173a729932f Mon Sep 17 00:00:00 2001
From: "Guillermo E. Martinez via Libabigail" <libabigail@sourceware.org>
Date: Fri, 30 Sep 2022 19:15:44 -0500
Subject: [PATCH] use CTF as a fallback when no DWARF debug info is present

By default, `abidw', `abidiff', `abipkgdiff' and `kmidiff' tools use
debug information in `DWARF` format, if present.

With this patch however, if no DWARF debug info was found, these tools
automatically try to use the CTF debug information without needing the
`--ctf' option flag.  If no DWARF or CTF debug information were found,
the tools rely only on `ELF` symbols.

As the tools don't allow comparing corpora constructed using different
debug information i.e DWARF vs CTF, the first corpus built dictates
the expected debug information in the second one.

This works for libraries and Linux kernel.  The `--ctf' option is
preserved to explicitly indicate to those tools that we want to use
CTF support.

	* 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.
	* src/abg-ctf-reader.cc (slurp_elf_info): Report status
	when debug information is not present.
	(read_corpus): Add code to locate `vmlinux.ctfa' just when
	`main corpus' is being processed.
	* src/abg-tools-utils.cc (maybe_load_vmlinux_dwarf_corpus)
	(maybe_load_vmlinux_ctf_corpus): Return the status of the loading.
	(build_corpus_group_from_kernel_dist_under): If loading the DWARF
	debug info was not successful, try loading the CTF debug info.
	* tests/data/test-diff-pkg-ctf/dirpkg-3-report-2.txt: Adjust
	test case.
	* tests/test-diff-pkg.cc (in_out_specs): Add `--ctf' option
	in test case.
	* tools/abidiff.cc (main): If loading the debug info assuming
	DWARF failed, then try with CTF.
	* tools/abidw.cc: Likewise.
	* tools/abipkgdiff.cc: Likewise.

Signed-off-by: Guillermo E. Martinez <guillermo.e.martinez@oracle.com>
Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 doc/manuals/abidiff.rst                       | 15 +--
 doc/manuals/abidw.rst                         | 15 ++-
 doc/manuals/abipkgdiff.rst                    | 13 ++-
 doc/manuals/kmidiff.rst                       |  9 +-
 include/abg-tools-utils.h                     |  4 +
 src/abg-ctf-reader.cc                         | 33 ++++---
 src/abg-tools-utils.cc                        | 70 +++++++++++---
 .../test-diff-pkg-ctf/dirpkg-3-report-2.txt   | 16 ++++
 tests/test-diff-pkg.cc                        |  2 +-
 tools/abidiff.cc                              | 68 +++++++++++++-
 tools/abidw.cc                                | 49 ++++++++--
 tools/abipkgdiff.cc                           | 92 ++++++++++++++++++-
 12 files changed, 330 insertions(+), 56 deletions(-)

diff --git a/doc/manuals/abidiff.rst b/doc/manuals/abidiff.rst
index 0c711d9e..5d0834cd 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, only `ELF`_
+symbols that were added or removed are reported.
 
 .. include:: tools-use-libabigail.txt
 
@@ -558,7 +559,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``
@@ -785,4 +786,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..c162ef25 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 the ABI or KMI representation, by default ``abidw`` uses
+debug information in the `DWARF`_ format, if present, otherwise it
+looks for the debug information in the `CTF`_ format.  Finally, if
+neither is found, it only reports which `ELF`_ symbols 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..086762d5 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 the 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 reports about `ELF`_ symbols that 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..4059c71f 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 the 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 only
+reports about `ELF`_ symbols that 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-tools-utils.h b/include/abg-tools-utils.h
index 27bbfefe..391a389a 100644
--- a/include/abg-tools-utils.h
+++ b/include/abg-tools-utils.h
@@ -297,6 +297,10 @@ bool
 file_is_kernel_debuginfo_package(const string& file_path,
 				 file_type file_type);
 
+bool
+dir_contains_ctf_archive(const string& directory,
+			 const string& archive_prefix);
+
 std::shared_ptr<char>
 make_path_absolute(const char*p);
 
diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index e307fcd7..bcd011d3 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -45,6 +45,7 @@ namespace ctf_reader
 using std::dynamic_pointer_cast;
 using abigail::tools_utils::dir_name;
 using abigail::tools_utils::file_exists;
+using abigail::tools_utils::base_name;
 
 class read_context
 {
@@ -1524,7 +1525,12 @@ slurp_elf_info(read_context *ctxt,
   corp->set_architecture_name(elf_helpers::e_machine_to_string(ehdr->e_machine));
 
   find_alt_debuginfo(ctxt, &ctf_dbg_scn);
-  ABG_ASSERT(ctxt->symtab);
+  if (!ctxt->symtab)
+    {
+      status |= elf_reader::STATUS_NO_SYMBOLS_FOUND;
+      return;
+    }
+
   corp->set_symtab(ctxt->symtab);
 
   if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
@@ -1543,7 +1549,8 @@ slurp_elf_info(read_context *ctxt,
         ctf_scn = ctf_dbg_scn;
       else
         {
-          status |= elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
+          status |= (elf_reader::STATUS_OK |
+                     elf_reader::STATUS_DEBUG_INFO_NOT_FOUND);
           return;
         }
     }
@@ -1655,15 +1662,15 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
     origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
   corp->set_origin(origin);
 
-  if (ctxt->cur_corpus_group_)
-    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
-
   slurp_elf_info(ctxt, corp, status);
-  if (!is_linux_kernel
-      && ((status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND) |
-          (status & elf_reader::STATUS_NO_SYMBOLS_FOUND)))
+  if ((status & elf_reader::STATUS_NO_SYMBOLS_FOUND) ||
+      (!is_linux_kernel &&
+       (status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)))
       return corp;
 
+  if (ctxt->cur_corpus_group_)
+    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
+
   // Set the set of exported declaration that are defined.
   ctxt->exported_decls_builder
    (ctxt->cur_corpus_->get_exported_decls_builder().get());
@@ -1674,9 +1681,13 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
     {
       if (ctxt->ctfa == NULL)
         {
-          std::string ctfa_filename;
-          if (find_ctfa_file(ctxt, ctfa_filename))
-            ctxt->ctfa = ctf_arc_open(ctfa_filename.c_str(), &errp);
+          std::string filename;
+          base_name(ctxt->filename, filename);
+
+          // locate vmlinux.ctfa only when reader is processing
+          // vmlinux file, i.e the main corpus in the group.
+          if (filename == "vmlinux" && find_ctfa_file(ctxt, filename))
+            ctxt->ctfa = ctf_arc_open(filename.c_str(), &errp);
         }
     }
   else
diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
index fe9ebc72..a23f08ea 100644
--- a/src/abg-tools-utils.cc
+++ b/src/abg-tools-utils.cc
@@ -1694,6 +1694,23 @@ file_is_kernel_debuginfo_package(const string& file_name, file_type file_type)
   return result;
 }
 
+/// 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;
+}
+
 /// The delete functor of a char buffer that has been created using
 /// malloc.
 struct malloced_char_star_deleter
@@ -2525,8 +2542,12 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
 /// @param t time to trace time spent in each step.
 ///
 /// @param env the environment to create the corpus_group in.
-static void
-maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
+///
+/// @return the status of the loading.  If it's
+/// abigail::elf_reader::STATUS_UNKNOWN, then it means nothing was
+/// done, meaning the function got out early.
+static abigail::elf_reader::status
+maybe_load_vmlinux_dwarf_corpus(corpus::origin&     origin,
                                 corpus_group_sptr&  group,
                                 const string&       vmlinux,
                                 vector<string>&     modules,
@@ -2539,10 +2560,11 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
                                 timer&              t,
                                 environment_sptr&   env)
 {
+  abigail::elf_reader::status status = abigail::elf_reader::STATUS_UNKNOWN;
+
   if (!(origin & corpus::DWARF_ORIGIN))
-    return;
+    return status;
 
-  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
   dwarf_reader::read_context_sptr ctxt;
   ctxt =
    dwarf_reader::create_read_context(vmlinux, di_roots, env.get(),
@@ -2569,6 +2591,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
      << vmlinux << "' ...\n" << std::flush;
 
   // Read the vmlinux corpus and add it to the group.
+  status = abigail::elf_reader::STATUS_OK;
   t.start();
   read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
   t.stop();
@@ -2579,7 +2602,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
      << t << "\n";
 
   if (group->is_empty())
-    return;
+    return status;
 
   // Now add the corpora of the modules to the corpus group.
   int total_nb_modules = modules.size();
@@ -2614,6 +2637,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
          << "' reading DONE: "
          << t << "\n";
     }
+  return status;
 }
 
 /// If the @ref origin is CTF_ORIGIN it build a @ref corpus_group
@@ -2642,8 +2666,12 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
 /// @param t time to trace time spent in each step.
 ///
 /// @param env the environment to create the corpus_group in.
+///
+/// @return the status of the loading.  If it's
+/// abigail::elf_reader::STATUS_UNKNOWN, then it means nothing was
+/// done, meaning the function got out early.
 #ifdef WITH_CTF
-static void
+static abigail::elf_reader::status
 maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
                               corpus_group_sptr&  group,
                               const string&       vmlinux,
@@ -2654,10 +2682,11 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
                               timer&              t,
                               environment_sptr&   env)
 {
+  abigail::elf_reader::status status = abigail::elf_reader::STATUS_UNKNOWN;
+
   if (!(origin & corpus::CTF_ORIGIN))
-    return;
+    return status;
 
-  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
   ctf_reader::read_context_sptr ctxt;
   ctxt = ctf_reader::create_read_context(vmlinux, di_roots, env.get());
   group.reset(new corpus_group(env.get(), root));
@@ -2668,6 +2697,7 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
      << vmlinux << "' ...\n" << std::flush;
 
   // Read the vmlinux corpus and add it to the group.
+  status = abigail::elf_reader::STATUS_OK;
   t.start();
   read_and_add_corpus_to_group_from_elf(ctxt.get(), *group, status);
   t.stop();
@@ -2678,7 +2708,7 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
      << t << "\n";
 
   if (group->is_empty())
-    return;
+    return status;
 
   // Now add the corpora of the modules to the corpus group.
   int total_nb_modules = modules.size();
@@ -2707,6 +2737,7 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
          << "' reading DONE: "
          << t << "\n";
     }
+  return status;
 }
 #endif
 
@@ -2786,14 +2817,23 @@ 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_reader::status status =
+	maybe_load_vmlinux_dwarf_corpus(origin, group, vmlinux,
+					modules, root, di_roots,
+					suppr_paths, kabi_wl_paths,
+					supprs, verbose, t, env);
 #ifdef WITH_CTF
+      string vmlinux_basename;
+      base_name(vmlinux, vmlinux_basename);
+      if (origin == corpus::DWARF_ORIGIN
+	  && (status & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
+	  && dir_contains_ctf_archive(root, vmlinux_basename))
+	  // Let's try to load the binary using the CTF archive!
+	origin |= corpus::CTF_ORIGIN;
+
       maybe_load_vmlinux_ctf_corpus(origin, group, vmlinux,
-                                    modules, root, di_roots,
-                                    verbose, t, env);
+				    modules, root, di_roots,
+				    verbose, t, env);
 #endif
     }
 
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/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/tools/abidiff.cc b/tools/abidiff.cc
index e0bb35ac..0d9e59c2 100644
--- a/tools/abidiff.cc
+++ b/tools/abidiff.cc
@@ -47,6 +47,9 @@ using abigail::suppr::suppressions_type;
 using abigail::suppr::read_suppressions;
 using namespace abigail::dwarf_reader;
 using namespace abigail::elf_reader;
+using abigail::tools_utils::base_name;
+using abigail::tools_utils::dir_name;
+using abigail::tools_utils::dir_contains_ctf_archive;
 using abigail::tools_utils::emit_prefix;
 using abigail::tools_utils::check_file;
 using abigail::tools_utils::guess_file_type;
@@ -1205,6 +1208,36 @@ main(int argc, char* argv[])
                 set_suppressions(*ctxt, opts);
                 abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
                 c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
+
+#ifdef WITH_CTF
+		if (// We were not instructed to use CTF ...
+		    !opts.use_ctf
+		    // ... and yet, no debug info was found ...
+		    && (c1_status & STATUS_DEBUG_INFO_NOT_FOUND)
+		    // ... but we found ELF symbols ...
+		    && !(c1_status & STATUS_NO_SYMBOLS_FOUND))
+		  {
+		    string basenam, dirnam;
+		    base_name(opts.file1, basenam);
+		    dir_name(opts.file1, dirnam);
+		    // ... the input file seems to contain CTF
+		    // archive, so let's try to see if the file
+		    // contains a CTF archive, who knows ...
+		    if (dir_contains_ctf_archive(dirnam, basenam))
+		      {
+			// The file does contain CTF debug information finally!
+			abigail::ctf_reader::read_context_sptr ctxt =
+			  abigail::ctf_reader::create_read_context
+			  (opts.file1,
+			   opts.prepared_di_root_paths1,
+			   env.get());
+			ABG_ASSERT(ctxt);
+
+			c1 = abigail::ctf_reader::read_corpus(ctxt.get(),
+							      c1_status);
+		      }
+		  }
+#endif
                 if (!c1
                     || (opts.fail_no_debug_info
                         && (c1_status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
@@ -1212,7 +1245,7 @@ main(int argc, char* argv[])
                   return handle_error(c1_status, ctxt.get(),
                                       argv[0], opts);
               }
-	  }
+          }
 	  break;
 	case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
 	  {
@@ -1289,13 +1322,44 @@ main(int argc, char* argv[])
                 set_suppressions(*ctxt, opts);
 
                 c2 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c2_status);
+
+#ifdef WITH_CTF
+		if (// We were not instructed to use CTF ...
+		    !opts.use_ctf
+		    // ... and yet, no debug info was found ...
+		    && (c2_status & STATUS_DEBUG_INFO_NOT_FOUND)
+		    // ... but we found ELF symbols ...
+		    && !(c2_status & STATUS_NO_SYMBOLS_FOUND))
+		  {
+		    string basenam, dirnam;
+		    base_name(opts.file2, basenam);
+		    dir_name(opts.file2, dirnam);
+		    // ... the input file seems to contain CTF
+		    // archive, so let's try to see if the file
+		    // contains a CTF archive, who knows ...
+		      if (dir_contains_ctf_archive(dirnam, basenam))
+		      {
+			// The file does contain CTF debug information finally!
+			abigail::ctf_reader::read_context_sptr ctxt =
+			  abigail::ctf_reader::create_read_context
+			  (opts.file2,
+			   opts.prepared_di_root_paths2,
+			   env.get());
+			ABG_ASSERT(ctxt);
+
+			c2 = abigail::ctf_reader::read_corpus(ctxt.get(),
+							      c2_status);
+		      }
+		  }
+#endif
+
                 if (!c2
                     || (opts.fail_no_debug_info
                         && (c2_status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
                         && (c2_status & STATUS_DEBUG_INFO_NOT_FOUND)))
                   return handle_error(c2_status, ctxt.get(), argv[0], opts);
               }
-	  }
+          }
 	  break;
 	case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
 	  {
diff --git a/tools/abidw.cc b/tools/abidw.cc
index f38d6048..c68a30f4 100644
--- a/tools/abidw.cc
+++ b/tools/abidw.cc
@@ -41,6 +41,9 @@ using std::ofstream;
 using std::vector;
 using std::shared_ptr;
 using abg_compat::optional;
+using abigail::tools_utils::base_name;
+using abigail::tools_utils::dir_name;
+using abigail::tools_utils::dir_contains_ctf_archive;
 using abigail::tools_utils::emit_prefix;
 using abigail::tools_utils::temp_file;
 using abigail::tools_utils::temp_file_sptr;
@@ -557,16 +560,16 @@ load_corpus_and_write_abixml(char* argv[],
   if (opts.use_ctf)
     {
       abigail::ctf_reader::read_context_sptr ctxt
-        = abigail::ctf_reader::create_read_context(opts.in_file_path,
-                                                   opts.prepared_di_root_paths,
-                                                   env.get());
+	= abigail::ctf_reader::create_read_context(opts.in_file_path,
+						   opts.prepared_di_root_paths,
+						   env.get());
       assert (ctxt);
       t.start();
       corp = abigail::ctf_reader::read_corpus (ctxt, s);
       t.stop();
       if (opts.do_log)
-        emit_prefix(argv[0], cerr)
-          << "read corpus from elf file in: " << t << "\n";
+	emit_prefix(argv[0], cerr)
+	  << "read corpus from elf file in: " << t << "\n";
     }
   else
 #endif
@@ -616,7 +619,7 @@ load_corpus_and_write_abixml(char* argv[],
         }
 
       if (opts.exported_interfaces_only.has_value())
-	env->analyze_exported_interfaces_only(*opts.exported_interfaces_only);
+        env->analyze_exported_interfaces_only(*opts.exported_interfaces_only);
 
       t.start();
       corp = dwarf_reader::read_corpus_from_elf(ctxt, s);
@@ -632,6 +635,38 @@ load_corpus_and_write_abixml(char* argv[],
       if (opts.do_log)
         emit_prefix(argv[0], cerr)
           << "reset read context in: " << t << "\n";
+
+#ifdef WITH_CTF
+      if (// We were not instructed to use CTF ...
+	  !opts.use_ctf
+	  // ... and yet, no debug info was found ...
+	  && (s & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
+	  // ... but we found ELF symbols ...
+	  && !(s & abigail::elf_reader::STATUS_NO_SYMBOLS_FOUND))
+	{
+	  string basenam, dirnam;
+	  base_name(opts.in_file_path, basenam);
+	  dir_name(opts.in_file_path, dirnam);
+	  // ... the input file seems to contain CTF
+	  // archive, so let's try to see if the file
+	  // contains a CTF archive, who knows ...
+	  if (dir_contains_ctf_archive(dirnam, basenam))
+	    {
+	      abigail::ctf_reader::read_context_sptr ctxt
+		= abigail::ctf_reader::create_read_context(opts.in_file_path,
+							   opts.prepared_di_root_paths,
+							   env.get());
+	      assert (ctxt);
+	      t.start();
+	      corp = abigail::ctf_reader::read_corpus (ctxt, s);
+	      t.stop();
+
+	      if (opts.do_log)
+		emit_prefix(argv[0], cerr)
+		  << "read CTF corpus from elf file in:" << t << "\n";
+	    }
+	}
+#endif
     }
 
   // If we couldn't create a corpus, emit some (hopefully) useful
@@ -834,7 +869,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 656d5882..e7bb5c37 100644
--- a/tools/abipkgdiff.cc
+++ b/tools/abipkgdiff.cc
@@ -127,6 +127,7 @@ using abigail::tools_utils::make_path_absolute;
 using abigail::tools_utils::base_name;
 using abigail::tools_utils::get_rpm_arch;
 using abigail::tools_utils::file_is_kernel_package;
+using abigail::tools_utils::dir_contains_ctf_archive;
 using abigail::tools_utils::gen_suppr_spec_from_headers;
 using abigail::tools_utils::get_default_system_suppression_file_path;
 using abigail::tools_utils::get_default_user_suppression_file_path;
@@ -1346,6 +1347,34 @@ compare(const elf_file& elf1,
           add_read_context_suppressions(*ctxt_dwarf, opts.kabi_suppressions);
 
         corpus1 = read_corpus_from_elf(*ctxt_dwarf, c1_status);
+
+#ifdef WITH_CTF
+	if (// We were not instructed to use CTF ...
+	    !opts.use_ctf
+	    // ... and yet, no debug info was found ...
+	    && (c1_status & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
+	    // ... but we found ELF symbols ...
+	    && !(c1_status & abigail::elf_reader::STATUS_NO_SYMBOLS_FOUND))
+	  {
+	    string basenam, dirnam;
+	    base_name(elf1.path, basenam);
+	    dir_name(elf1.path, dirnam);
+	    // ... the input file seems to contain CTF
+	    // archive, so let's try to see if the file
+	    // contains a CTF archive, who knows ...
+	    if (dir_contains_ctf_archive(dirnam, basenam))
+	      {
+		// The file does contain CTF debug information
+		// finally!
+		ctxt_ctf = abigail::ctf_reader::create_read_context(elf1.path,
+								    di_dirs1,
+								    env.get());
+		ABG_ASSERT(ctxt_ctf);
+		corpus1 = abigail::ctf_reader::read_corpus(ctxt_ctf.get(),
+							   c1_status);
+	      }
+	  }
+#endif
       }
 
     bool bail_out = false;
@@ -1451,6 +1480,34 @@ compare(const elf_file& elf1,
           add_read_context_suppressions(*ctxt_dwarf, opts.kabi_suppressions);
 
         corpus2 = read_corpus_from_elf(*ctxt_dwarf, c2_status);
+
+#ifdef WITH_CTF
+	if (// We were not instructed to use CTF ...
+	    !opts.use_ctf
+	    // ... and yet, no debug info was found ...
+	    && (c2_status & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
+	    // ... but we found ELF symbols ...
+	    && !(c2_status & abigail::elf_reader::STATUS_NO_SYMBOLS_FOUND))
+	  {
+	    string basenam, dirnam;
+	    base_name(elf2.path, basenam);
+	    dir_name(elf2.path, dirnam);
+	    // ... the input file seems to contain CTF
+	    // archive, so let's try to see if the file
+	    // contains a CTF archive, who knows ...
+	    if (dir_contains_ctf_archive(dirnam, basenam))
+	      {
+		// The file does contain CTF debug information
+		// finally!
+		ctxt_ctf = abigail::ctf_reader::create_read_context(elf2.path,
+								    di_dirs2,
+								    env.get());
+		ABG_ASSERT(ctxt_ctf);
+		corpus2 = abigail::ctf_reader::read_corpus(ctxt_ctf.get(),
+							   c2_status);
+	      }
+	  }
+#endif
       }
 
     bool bail_out = false;
@@ -1612,17 +1669,44 @@ compare_to_self(const elf_file& elf,
 							    di_dirs,
                                                             env.get());
         ABG_ASSERT(ctxt_ctf);
-        corp = abigail::ctf_reader::read_corpus(ctxt_ctf.get(),
-                                                   c_status);
+        corp = abigail::ctf_reader::read_corpus(ctxt_ctf.get(), c_status);
       }
     else
 #endif
       {
         ctxt_dwarf =
-         create_read_context(elf.path, di_dirs, env.get(),
-                             /*read_all_types=*/opts.show_all_types);
+	  create_read_context(elf.path, di_dirs, env.get(),
+			      /*read_all_types=*/opts.show_all_types);
 
         corp = read_corpus_from_elf(*ctxt_dwarf, c_status);
+
+#ifdef WITH_CTF
+	if (// We were not instructed to use CTF ...
+	    !opts.use_ctf
+	    // ... and yet, no debug info was found ...
+	    && (c_status & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
+	    // ... but we found ELF symbols ...
+	    && !(c_status & abigail::elf_reader::STATUS_NO_SYMBOLS_FOUND))
+	  {
+	    string basenam, dirnam;
+	    base_name(elf.path, basenam);
+	    dir_name(elf.path, dirnam);
+	    // ... the input file seems to contain CTF
+	    // archive, so let's try to see if the file
+	    // contains a CTF archive, who knows ...
+	    if (dir_contains_ctf_archive(dirnam, basenam))
+	      {
+		// The file does contain CTF debug information
+		// finally!
+		ctxt_ctf = abigail::ctf_reader::create_read_context(elf.path,
+								    di_dirs,
+								    env.get());
+		ABG_ASSERT(ctxt_ctf);
+		corp = abigail::ctf_reader::read_corpus(ctxt_ctf.get(),
+							c_status);
+	      }
+	  }
+#endif
       }
 
     if (!(c_status & abigail::elf_reader::STATUS_OK))
-- 
2.38.0.rc2


-- 
		Dodji

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

* Re: [PATCH] CTF as a fallback when no DWARF debug info is present
  2022-10-04  9:04 ` Dodji Seketeli
@ 2022-10-04 23:13   ` Guillermo E. Martinez
  2022-10-06  7:42     ` Dodji Seketeli
  0 siblings, 1 reply; 17+ messages in thread
From: Guillermo E. Martinez @ 2022-10-04 23:13 UTC (permalink / raw)
  To: Dodji Seketeli, Guillermo E. Martinez via Libabigail



On 10/4/22 04:04, Dodji Seketeli wrote:
> Hello Guillermo,
>

HI Dodji,
  
> Thank you for this patch.
> 
Your welcome!.

> Please find my comments below.
> 
> "Guillermo E. Martinez via Libabigail" <libabigail@sourceware.org> a
> écrit:
> 
> 
>> 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 binaries 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 which of them were added or removed.
>>
>> In case of neither DWARF nor CTF debug information is present
>> (`STATUS_DEBUG_INFO_NOT_FOUND') and `--ctf' option was not passed in
>> the command line, those tools use the symbol object build by DWARF
>> reader (default) to completed  theirs task.
>>
>> Tools don't allow comparing corpora built with between different debug
>> information i.e DWARF vs CTF, the first corpus built dictate the
>> expected debug information in the second one.
>>
>> This work for libraries and Linux kernel.  The `--ctf' option is
>> preserved to explicitly indicate to those tools that we want to use
>> CTF support.
>>
>> 	* 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.
> 
> I have made some slight fixes to changes to these doc files.  Nothing
> major you'll see the changes in the updated version of the patch that I
> am posting at the end of this message.
> 

OK.

> [...]
> 
>> 	* src/abg-ctf-reader.cc (slurp_elf_info): Report status
>> 	when debug information is not present.
>> 	(read_corpus): Add code to locate `vmlinux.ctfa' just when
>> 	`main corpus' is being processed.
>> 	* src/abg-tools-utils.cc (maybe_load_vmlinux_dwarf_corpus):
>> 	Replace by a reference `origin' argument to notify whether
>> 	CTF reader needs to be executed.
>> 	* tests/data/test-diff-pkg-ctf/dirpkg-3-report-2.txt: Adjust
>> 	test case.
>> 	* tests/test-diff-pkg.cc (in_out_specs): Add `--ctf' option
>> 	in test case.
>> 	* tools/abidiff.cc (main): Add `origin' depending of command
>> 	line argument by default it is `corpus::DWARF_ORIGIN'. Add
>> 	`dwarf_corpus' to be used as default corpus (containing ELF
>> 	symbols), when DWARF nor CTF debug information was found.
>> 	* 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 +-
>>   src/abg-ctf-reader.cc                         |  33 +++--
>>   src/abg-tools-utils.cc                        |  22 +++-
>>   .../test-diff-pkg-ctf/dirpkg-3-report-2.txt   |  16 +++
>>   tests/test-diff-pkg.cc                        |   2 +-
>>   tools/abidiff.cc                              |  82 ++++++++-----
>>   tools/abidw.cc                                |  54 +++++---
>>   tools/abipkgdiff.cc                           | 116 +++++++++++-------
>>   11 files changed, 257 insertions(+), 120 deletions(-)
>>
>> diff --git a/doc/manuals/abidiff.rst b/doc/manuals/abidiff.rst
>> index 0c711d9e..caeceded 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
>>   
>> @@ -558,7 +559,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``
>> @@ -785,4 +786,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/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
>> index 9148a646..b3cde365 100644
>> --- a/src/abg-ctf-reader.cc
>> +++ b/src/abg-ctf-reader.cc
>> @@ -45,6 +45,7 @@ namespace ctf_reader
>>   using std::dynamic_pointer_cast;
>>   using abigail::tools_utils::dir_name;
>>   using abigail::tools_utils::file_exists;
>> +using abigail::tools_utils::base_name;
>>   
>>   class read_context
>>   {
>> @@ -1545,7 +1546,12 @@ slurp_elf_info(read_context *ctxt,
>>     corp->set_architecture_name(elf_helpers::e_machine_to_string(ehdr->e_machine));
>>   
>>     find_alt_debuginfo(ctxt, &ctf_dbg_scn);
>> -  ABG_ASSERT(ctxt->symtab);
>> +  if (!ctxt->symtab)
>> +    {
>> +      status |= elf_reader::STATUS_NO_SYMBOLS_FOUND;
>> +      return;
>> +    }
>> +
>>     corp->set_symtab(ctxt->symtab);
>>   
>>     if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
>> @@ -1564,7 +1570,8 @@ slurp_elf_info(read_context *ctxt,
>>           ctf_scn = ctf_dbg_scn;
>>         else
>>           {
>> -          status |= elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
>> +          status |= (elf_reader::STATUS_OK |
>> +                     elf_reader::STATUS_DEBUG_INFO_NOT_FOUND);
>>             return;
>>           }
>>       }
>> @@ -1676,15 +1683,15 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
>>       origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
>>     corp->set_origin(origin);
>>   
>> -  if (ctxt->cur_corpus_group_)
>> -    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
>> -
>>     slurp_elf_info(ctxt, corp, status);
>> -  if (!is_linux_kernel
>> -      && ((status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND) |
>> -          (status & elf_reader::STATUS_NO_SYMBOLS_FOUND)))
>> +  if ((status & elf_reader::STATUS_NO_SYMBOLS_FOUND) ||
>> +      (!is_linux_kernel &&
>> +       (status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)))
>>         return corp;
>>   
>> +  if (ctxt->cur_corpus_group_)
>> +    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
>> +
>>     // Set the set of exported declaration that are defined.
>>     ctxt->exported_decls_builder
>>      (ctxt->cur_corpus_->get_exported_decls_builder().get());
>> @@ -1695,9 +1702,13 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
>>       {
>>         if (ctxt->ctfa == NULL)
>>           {
>> -          std::string ctfa_filename;
>> -          if (find_ctfa_file(ctxt, ctfa_filename))
>> -            ctxt->ctfa = ctf_arc_open(ctfa_filename.c_str(), &errp);
>> +          std::string filename;
>> +          base_name(ctxt->filename, filename);
>> +
>> +          // locate vmlinux.ctfa only when reader is processing
>> +          // vmlinux file, i.e the main corpus in the group.
>> +          if (filename == "vmlinux" && find_ctfa_file(ctxt, filename))
>> +            ctxt->ctfa = ctf_arc_open(filename.c_str(), &errp);
>>           }
>>       }
>>     else
>> diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
>> index fe9ebc72..7d00f726 100644
>> --- a/src/abg-tools-utils.cc
>> +++ b/src/abg-tools-utils.cc
>> @@ -2493,6 +2493,11 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
>>   /// made of vmlinux kernel file and the linux kernel modules found
>>   /// under @p root directory and under its sub-directories, recursively.
>>   ///
>> +/// If the vmlinux file doens't have DWARF info, it looks for
>> +/// vmlinux.ctfa, if it's present, it assumes that kernel was build
>> +/// with CTF support, then it updates @ref origin, given chance to
>> +/// CTF reader to build the IR for kernel build directory.
>> +///
>>   /// @param origin the debug type information in vmlinux kernel and
>>   /// the linux kernel modules to be used to build the corpora @p group.
>>   ///
>> @@ -2526,7 +2531,7 @@ 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,
>> +maybe_load_vmlinux_dwarf_corpus(corpus::origin      &origin,
>>                                   corpus_group_sptr&  group,
>>                                   const string&       vmlinux,
>>                                   vector<string>&     modules,
>> @@ -2578,6 +2583,21 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>>        << " reading DONE:"
>>        << t << "\n";
>>   
>> +  if (status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
>> +    {
>> +      // vmlinux doesn't have DWARF debug info, so it might contain
>> +      // CTF debug info, this means vmlinux.ctfa is under kernel
>> +      // build directory.
>> +      string ctfa_file = root + "/vmlinux.ctfa";
>> +      if (file_exists(ctfa_file))
>> +        {
>> +          // OK. Likely CTF could build a better IR, then let's
>> +          // notify the caller to try with CTF reader.
>> +          origin = corpus::CTF_ORIGIN;
>> +          return;
>> +        }
>> +    }
>> +
> 
> Hmmh, I think this change is done at logical level that is too "low",
> compared to the level at which I believe this decision should be made.
> Namely, maybe_load_vmlinux_dwarf_corpus is meant to try to load DWARF
> debug information.  It should not deal with CTF debug information
> (looking for CTF archive files etc).  Rather, I think that if the
> loading of DWARF failed, that function should tell its caller about it.
> It would thus be up to the caller to decide what to do with that
> information. For instance, the caller would then be able to try and load
> CTF debug information instead.
> 

Ohh. I see, much better.

> So I would rather modify maybe_load_vmlinux_dwarf_corpus to make it
> return the status of the loading, so that the caller can know if the
> loading succeeded or not.
> 

Yes. totally agree.

> So here is the change I would propose for the
> maybe_load_vmlinux_dwarf_corpus and maybe_load_vmlinux_ctf_corpus
> functions instead (it's part of the whole patch that I have posted at
> the end of this message):
> 
>      @@ -2525,8 +2542,12 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
>       /// @param t time to trace time spent in each step.
>       ///
>       /// @param env the environment to create the corpus_group in.
>      -static void
>      -maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>      +///
>      +/// @return the status of the loading.  If it's
>      +/// abigail::elf_reader::STATUS_UNKNOWN, then it means nothing was
>      +/// done, meaning the function got out early.
>      +static abigail::elf_reader::status
>      +maybe_load_vmlinux_dwarf_corpus(corpus::origin&     origin,
>                                       corpus_group_sptr&  group,
>                                       const string&       vmlinux,
>                                       vector<string>&     modules,
>      @@ -2539,10 +2560,11 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>                                       timer&              t,
>                                       environment_sptr&   env)
>       {
>      +  abigail::elf_reader::status status = abigail::elf_reader::STATUS_UNKNOWN;
>      +
>         if (!(origin & corpus::DWARF_ORIGIN))
>      -    return;
>      +    return status;
> 
>      -  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
>         dwarf_reader::read_context_sptr ctxt;
>         ctxt =
>          dwarf_reader::create_read_context(vmlinux, di_roots, env.get(),
>      @@ -2569,6 +2591,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>            << vmlinux << "' ...\n" << std::flush;
> 
>         // Read the vmlinux corpus and add it to the group.
>      +  status = abigail::elf_reader::STATUS_OK;
>         t.start();
>         read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
>         t.stop();
>      @@ -2579,7 +2602,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>            << t << "\n";
> 

At this point if `vmlinux' file doesn't have DWARF information, the `status'
returned by `maybe_load_vmlinux_dwarf_corpus' will set the bit field
`STATUS_DEBUG_INFO_NOT_FOUND', but it is not verified here, and since vmlinux
corpus was already added into the group in `read_debug_info_into_corpus'
function, it continues processing modules without the main corpus information,
Is this the expected behaviour?
  
>         if (group->is_empty())
>      -    return;
>      +    return status;
> 
>         // Now add the corpora of the modules to the corpus group.
>         int total_nb_modules = modules.size();
>      @@ -2614,6 +2637,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>                << "' reading DONE: "
>                << t << "\n";
>           }
>      +  return status;
>       }
> 
>       /// If the @ref origin is CTF_ORIGIN it build a @ref corpus_group
>      @@ -2642,8 +2666,12 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>       /// @param t time to trace time spent in each step.
>       ///
>       /// @param env the environment to create the corpus_group in.
>      +///
>      +/// @return the status of the loading.  If it's
>      +/// abigail::elf_reader::STATUS_UNKNOWN, then it means nothing was
>      +/// done, meaning the function got out early.
>       #ifdef WITH_CTF
>      -static void
>      +static abigail::elf_reader::status
>       maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
>                                     corpus_group_sptr&  group,
>                                     const string&       vmlinux,
>      @@ -2654,10 +2682,11 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
>                                     timer&              t,
>                                     environment_sptr&   env)
>       {
>      +  abigail::elf_reader::status status = abigail::elf_reader::STATUS_UNKNOWN;
>      +
>         if (!(origin & corpus::CTF_ORIGIN))
>      -    return;
>      +    return status;
> 
>      -  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
>         ctf_reader::read_context_sptr ctxt;
>         ctxt = ctf_reader::create_read_context(vmlinux, di_roots, env.get());
>         group.reset(new corpus_group(env.get(), root));
>      @@ -2668,6 +2697,7 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
>            << vmlinux << "' ...\n" << std::flush;
> 
>         // Read the vmlinux corpus and add it to the group.
>      +  status = abigail::elf_reader::STATUS_OK;
>         t.start();
>         read_and_add_corpus_to_group_from_elf(ctxt.get(), *group, status);
>         t.stop();
>      @@ -2678,7 +2708,7 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
>            << t << "\n";
> 
>         if (group->is_empty())
>      -    return;
>      +    return status;
> 
>         // Now add the corpora of the modules to the corpus group.
>         int total_nb_modules = modules.size();
>      @@ -2707,6 +2737,7 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
>                << "' reading DONE: "
>                << t << "\n";
>           }
>      +  return status;
>       }
>       #endif
> 
> I have also introduced a new function called
> tools_utils::dir_contains_ctf_archive to look for a file that ends with
> ".ctfa".  This abstracts away the search for "vmlinux.ctfa" as I wasn't
> sure if those archives could exist for normal (non-kernel) binaries as
> well:

Ohh, perfect!, I'll use it in CTF reader to located the Linux archive file.
No. there is no `.ctfa' file for non-kernel binaries intead they have `.ctf'
section, I could implement a similary function to looks for `.ctf' section
using elf helpers and it can be used in `load_corpus_and_write_abixml'
implementing a similar algorithm as with when we are processing the Kernel,
looking for DWARF information, and if it is not present then, test if
`.ctf' section is in ELF file then extract it using CTF reader,
to avoid duplication use of:

abigail::ctf_reader::read_context_sptr ctxt
		= abigail::ctf_reader::create_read_context(opts.in_file_path,
							   opts.prepared_di_root_paths,
							   env.get());

One for `opts.use_ctf' and other one when `STATUS_DEBUG_INFO_NOT_FOUND' is returned.
WDYT?

> 
>      diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
>      index fe9ebc72..a23f08ea 100644
>      --- a/src/abg-tools-utils.cc
>      +++ b/src/abg-tools-utils.cc
>      @@ -1694,6 +1694,23 @@ file_is_kernel_debuginfo_package(const string& file_name, file_type file_type)
>         return result;
>       }
> 
>      +/// 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;
>      +}
>      +
> 
> Then, now that the caller of these functions can know if loading the
> vmlinux binary succeeded or not, we can update that caller, which is
> build_corpus_group_from_kernel_dist_under:
> 
>      @@ -2786,14 +2817,23 @@ 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_reader::status status =
>      +	maybe_load_vmlinux_dwarf_corpus(origin, group, vmlinux,
>      +					modules, root, di_roots,
>      +					suppr_paths, kabi_wl_paths,
>      +					supprs, verbose, t, env);
>       #ifdef WITH_CTF
>      +      string vmlinux_basename;
>      +      base_name(vmlinux, vmlinux_basename);
>      +      if (origin == corpus::DWARF_ORIGIN
>      +	  && (status & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
>      +	  && dir_contains_ctf_archive(root, vmlinux_basename))
>      +	  // Let's try to load the binary using the CTF archive!
>      +	origin |= corpus::CTF_ORIGIN;
>      +
>             maybe_load_vmlinux_ctf_corpus(origin, group, vmlinux,
>      -                                    modules, root, di_roots,
>      -                                    verbose, t, env);
>      +				    modules, root, di_roots,
>      +				    verbose, t, env);
>       #endif
>           }
> 
> If you feel like we shouldn't test if the directory 'root' contains a
> ctf archive before trying to load the CTF archive, then please remove
> the call to dir_contains_ctf_archive above.  I just meant to show the
> general idea of where the decision should be made to try to load the ctf
> debug information, in my opinion.
>

Actually the `dir_contains_ctf_archive' prevents to rebuild/reset a group
in the CTF reader and discard the work done by DWARF reader if CTF information
is neither present in binary file.
  
> The general idea, however, is to make the reader of
> build_corpus_group_from_kernel_dist_under understand what is going on
> (that is, we try loading vmlinux with DWARF, and if it fails, then we
> try CTF) without having to go dig deep into how
> maybe_load_vmlinux_ctf_corpus works.
> 
> Similarly, I amended the changes to the tools (abi{diff,dw,pkgdiff}) to
> make them follow the same path.
> 
> [...]
> 
>> diff --git a/tools/abidiff.cc b/tools/abidiff.cc
>> index e0bb35ac..815c68df 100644
>> --- a/tools/abidiff.cc
>> +++ b/tools/abidiff.cc
>> @@ -1118,6 +1118,13 @@ main(int argc, char* argv[])
>>         return 0;
>>       }
>>   
>> +  corpus::origin first_input_origin;
>> +  corpus::origin origin =
>> +#ifdef WITH_CTF
>> +    opts.use_ctf ? corpus::CTF_ORIGIN :
>> +#endif
>> +    corpus::DWARF_ORIGIN;
>> +
> 
> I removed these changes above.  This is because we don't need to perform
> so many changes.  We can just let the code as it was and add new code to
> just one place to test if loading DWARF failed.  If it failed then we
> try to load CTF.
> 
> See below.
> 
>>     prepare_di_root_paths(opts);
>>   
>>     if (!maybe_check_suppression_files(opts))
>> @@ -1150,7 +1157,7 @@ main(int argc, char* argv[])
>>         abigail::elf_reader::status c1_status =
>>   	abigail::elf_reader::STATUS_OK,
>>   	c2_status = abigail::elf_reader::STATUS_OK;
>> -      corpus_sptr c1, c2;
>> +      corpus_sptr c1, c2, dwarf_corpus;
> 
> Likewise, removed.
> 
>>         corpus_group_sptr g1, g2;
>>         bool files_suppressed = false;
>>   
>> @@ -1180,20 +1187,9 @@ main(int argc, char* argv[])
>>   	case abigail::tools_utils::FILE_TYPE_ELF: // fall through
>>   	case abigail::tools_utils::FILE_TYPE_AR:
>>   	  {
>> -#ifdef WITH_CTF
>> -            if (opts.use_ctf)
>> -              {
>> -                abigail::ctf_reader::read_context_sptr ctxt
>> -                  = abigail::ctf_reader::create_read_context(opts.file1,
>> -                                                             opts.prepared_di_root_paths1,
>> -                                                             env.get());
>> -                ABG_ASSERT(ctxt);
>> -                c1 = abigail::ctf_reader::read_corpus(ctxt.get(),
>> -                                                      c1_status);
>> -              }
>> -            else
>> -#endif
> 
> I left this code in.  So no change here either.
> 
>> +            if (origin & corpus::DWARF_ORIGIN)
>>                 {
>> +                first_input_origin = corpus::DWARF_ORIGIN;
> 
> I remove this change as well.  So, still no change.
> 
>>                   abigail::dwarf_reader::read_context_sptr ctxt =
>>                     abigail::dwarf_reader::create_read_context
>>                     (opts.file1, opts.prepared_di_root_paths1,
>> @@ -1205,6 +1201,7 @@ main(int argc, char* argv[])
>>                   set_suppressions(*ctxt, opts);
>>                   abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
>>                   c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
>> +                dwarf_corpus = c1;
> 
> Likewise.
> 
> But then, it's here that we are going to inspect c1_status to see if
> loading DWARF failed.  If it failed, then we'll try to load CTF.  So,
> here is the change I am adding to the process of loading the corpus c1:
> 
> 
> @@ -1205,6 +1208,36 @@ main(int argc, char* argv[])
>                   set_suppressions(*ctxt, opts);
>                   abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
>                   c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
> +
> +#ifdef WITH_CTF
> +		if (// We were not instructed to use CTF ...
> +		    !opts.use_ctf

This is always true, because we are in the else block of `opts.use_ctf'.

> +		    // ... and yet, no debug info was found ...
> +		    && (c1_status & STATUS_DEBUG_INFO_NOT_FOUND)
> +		    // ... but we found ELF symbols ...
> +		    && !(c1_status & STATUS_NO_SYMBOLS_FOUND))
> +		  {
> +		    string basenam, dirnam;
> +		    base_name(opts.file1, basenam);
> +		    dir_name(opts.file1, dirnam);
> +		    // ... the input file seems to contain CTF
> +		    // archive, so let's try to see if the file
> +		    // contains a CTF archive, who knows ...
> +		    if (dir_contains_ctf_archive(dirnam, basenam))

Non-kernel binaries contains `.ctf' section instead of `ctfa' file,
so I can implement a `file_contains_ctf_section' function to test if
it is a valid input file for CTF reader.

> +		      {
> +			// The file does contain CTF debug information finally!
> +			abigail::ctf_reader::read_context_sptr ctxt =
> +			  abigail::ctf_reader::create_read_context
> +			  (opts.file1,
> +			   opts.prepared_di_root_paths1,
> +			   env.get());
> +			ABG_ASSERT(ctxt);
> +
> +			c1 = abigail::ctf_reader::read_corpus(ctxt.get(),
> +							      c1_status);
> +		      }
> +		  }
> +#endif
> 
> OK, maybe the statement
> 
>      "if (dir_contains_ctf_archive(dirnam, basenam))"
> 
> above is not necessary as I am not sure if the CTF archive file is
> supposed to be present for normal binaries or not.  If it's not
> necessary, then please remove that line as well as the use of the
> basenam/dirnam variables.
> 
> But you get the general idea.  We just test if loading DWARF failed
> (even if we were not instructed to use CTF) and then we try to load CTF.
> The change is at one place right after trying to load the DWARF,
> logically.
> 
> I do something similar to the loading of the second corpus c2.
> 
> 
> Here is the entire change to the abidiff file:
> 
>      diff --git a/tools/abidiff.cc b/tools/abidiff.cc
>      index e0bb35ac..0d9e59c2 100644
>      --- a/tools/abidiff.cc
>      +++ b/tools/abidiff.cc
>      @@ -47,6 +47,9 @@ using abigail::suppr::suppressions_type;
>       using abigail::suppr::read_suppressions;
>       using namespace abigail::dwarf_reader;
>       using namespace abigail::elf_reader;
>      +using abigail::tools_utils::base_name;
>      +using abigail::tools_utils::dir_name;
>      +using abigail::tools_utils::dir_contains_ctf_archive;
>       using abigail::tools_utils::emit_prefix;
>       using abigail::tools_utils::check_file;
>       using abigail::tools_utils::guess_file_type;
>      @@ -1205,6 +1208,36 @@ main(int argc, char* argv[])
>                       set_suppressions(*ctxt, opts);
>                       abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
>                       c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
>      +
>      +#ifdef WITH_CTF
>      +		if (// We were not instructed to use CTF ...
>      +		    !opts.use_ctf
>      +		    // ... and yet, no debug info was found ...
>      +		    && (c1_status & STATUS_DEBUG_INFO_NOT_FOUND)
>      +		    // ... but we found ELF symbols ...
>      +		    && !(c1_status & STATUS_NO_SYMBOLS_FOUND))
>      +		  {
>      +		    string basenam, dirnam;
>      +		    base_name(opts.file1, basenam);
>      +		    dir_name(opts.file1, dirnam);
>      +		    // ... the input file seems to contain CTF
>      +		    // archive, so let's try to see if the file
>      +		    // contains a CTF archive, who knows ...
>      +		    if (dir_contains_ctf_archive(dirnam, basenam))
>      +		      {
>      +			// The file does contain CTF debug information finally!
>      +			abigail::ctf_reader::read_context_sptr ctxt =
>      +			  abigail::ctf_reader::create_read_context
>      +			  (opts.file1,
>      +			   opts.prepared_di_root_paths1,
>      +			   env.get());
>      +			ABG_ASSERT(ctxt);
>      +
>      +			c1 = abigail::ctf_reader::read_corpus(ctxt.get(),
>      +							      c1_status);
>      +		      }
>      +		  }
>      +#endif
>                       if (!c1
>                           || (opts.fail_no_debug_info
>                               && (c1_status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
>      @@ -1212,7 +1245,7 @@ main(int argc, char* argv[])
>                         return handle_error(c1_status, ctxt.get(),
>                                             argv[0], opts);
>                     }
>      -	  }
>      +          }
>                break;
>              case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
>                {
>      @@ -1289,13 +1322,44 @@ main(int argc, char* argv[])
>                       set_suppressions(*ctxt, opts);
> 
>                       c2 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c2_status);
>      +
>      +#ifdef WITH_CTF
>      +		if (// We were not instructed to use CTF ...
>      +		    !opts.use_ctf
>      +		    // ... and yet, no debug info was found ...
>      +		    && (c2_status & STATUS_DEBUG_INFO_NOT_FOUND)
>      +		    // ... but we found ELF symbols ...
>      +		    && !(c2_status & STATUS_NO_SYMBOLS_FOUND))
>      +		  {
>      +		    string basenam, dirnam;
>      +		    base_name(opts.file2, basenam);
>      +		    dir_name(opts.file2, dirnam);
>      +		    // ... the input file seems to contain CTF
>      +		    // archive, so let's try to see if the file
>      +		    // contains a CTF archive, who knows ...
>      +		      if (dir_contains_ctf_archive(dirnam, basenam))
>      +		      {
>      +			// The file does contain CTF debug information finally!
>      +			abigail::ctf_reader::read_context_sptr ctxt =
>      +			  abigail::ctf_reader::create_read_context
>      +			  (opts.file2,
>      +			   opts.prepared_di_root_paths2,
>      +			   env.get());
>      +			ABG_ASSERT(ctxt);
>      +
>      +			c2 = abigail::ctf_reader::read_corpus(ctxt.get(),
>      +							      c2_status);
>      +		      }
>      +		  }
>      +#endif
>      +
>                       if (!c2
>                           || (opts.fail_no_debug_info
>                               && (c2_status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
>                               && (c2_status & STATUS_DEBUG_INFO_NOT_FOUND)))
>                         return handle_error(c2_status, ctxt.get(), argv[0], opts);
>                     }
>      -	  }
>      +          }
>                break;
>              case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
>                {
> 
> 
> By the way, I think there should be at least one test that exercises the
> workflow "try to load DWARF from the binary, fail, try to load CTF,
> succeed", without having the --ctf provided.  And we should have that
> test for all the tools that were modified.  We don't need to have that
> for a Linux Kernel, obviously, as that would be too big to have in the
> tarball.
> 

OK, I'll add test cases.

> Below is the entire amended patch that I came up with.  I suspect the
> use of the dir_contains_ctf_archive function everywhere is wrong, but
> I'll let you be the judge of that.  I think the documentation of when
> that archive is present/necessary would be good to improve/add.
> 
> Thanks again for the patch!

Thanks so much for comments!.

> 
> 
>  From 481b547d7871a544b690943b16e6a173a729932f Mon Sep 17 00:00:00 2001
> [...]

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

* Re: [PATCH] CTF as a fallback when no DWARF debug info is present
  2022-10-04 23:13   ` Guillermo E. Martinez
@ 2022-10-06  7:42     ` Dodji Seketeli
  2022-10-06 14:12       ` Dodji Seketeli
  2022-10-06 19:53       ` Guillermo Martinez
  0 siblings, 2 replies; 17+ messages in thread
From: Dodji Seketeli @ 2022-10-06  7:42 UTC (permalink / raw)
  To: Guillermo E. Martinez; +Cc: Guillermo E. Martinez via Libabigail

Hello Guillermo,

"Guillermo E. Martinez" <guillermo.e.martinez@oracle.com> a écrit:

[...]

>> I have also introduced a new function called
>> tools_utils::dir_contains_ctf_archive to look for a file that ends with
>> ".ctfa".  This abstracts away the search for "vmlinux.ctfa" as I wasn't
>> sure if those archives could exist for normal (non-kernel) binaries as
>> well:
>
> Ohh, perfect!, I'll use it in CTF reader to located the Linux archive file.

ACK.

[...]

>>      @@ -2525,8 +2542,12 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
>>       /// @param t time to trace time spent in each step.
>>       ///
>>       /// @param env the environment to create the corpus_group in.
>>      -static void
>>      -maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>>      +///
>>      +/// @return the status of the loading.  If it's
>>      +/// abigail::elf_reader::STATUS_UNKNOWN, then it means nothing was
>>      +/// done, meaning the function got out early.
>>      +static abigail::elf_reader::status
>>      +maybe_load_vmlinux_dwarf_corpus(corpus::origin&     origin,
>>                                       corpus_group_sptr&  group,
>>                                       const string&       vmlinux,
>>                                       vector<string>&     modules,
>>      @@ -2539,10 +2560,11 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>>                                       timer&              t,
>>                                       environment_sptr&   env)
>>       {
>>      +  abigail::elf_reader::status status = abigail::elf_reader::STATUS_UNKNOWN;
>>      +
>>         if (!(origin & corpus::DWARF_ORIGIN))
>>      -    return;
>>      +    return status;
>>
>>      -  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
>>         dwarf_reader::read_context_sptr ctxt;
>>         ctxt =
>>          dwarf_reader::create_read_context(vmlinux, di_roots, env.get(),
>>      @@ -2569,6 +2591,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>>            << vmlinux << "' ...\n" << std::flush;
>>
>>         // Read the vmlinux corpus and add it to the group.
>>      +  status = abigail::elf_reader::STATUS_OK;
>>         t.start();
>>         read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
>>         t.stop();
>>      @@ -2579,7 +2602,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>>            << t << "\n";
>>
>
> At this point if `vmlinux' file doesn't have DWARF information, the `status'
> returned by `maybe_load_vmlinux_dwarf_corpus' will set the bit field
> `STATUS_DEBUG_INFO_NOT_FOUND', but it is not verified here, and since vmlinux
> corpus was already added into the group in `read_debug_info_into_corpus'
> function, it continues processing modules without the main corpus information,

I see.  You are right.  Yes, the debug info is not found in vmlinux and yet the
whole thing continues, collecting just information from the ELF symbol
table, basically, and from the modules.  Pretty useless, I guess.

> Is this the expected behaviour?

Hehe, no :-)

I guess maybe the caller should look for the .debug_info section in the
vmlinux section (or for split debug info), prior to even calling
maybe_load_vmlinux_dwarf_corpus.  If there is no debug info, then the
function should proceed directly to calling
maybe_load_vmlinux_ctf_corpus?  What do you think?

[...]

>> I have also introduced a new function called
>> tools_utils::dir_contains_ctf_archive to look for a file that ends with
>> ".ctfa".  This abstracts away the search for "vmlinux.ctfa" as I wasn't
>> sure if those archives could exist for normal (non-kernel) binaries as
>> well:
>
> Ohh, perfect!, I'll use it in CTF reader to located the Linux archive file.
> No. there is no `.ctfa' file for non-kernel binaries intead they have `.ctf'
> section, I could implement a similary function to looks for `.ctf' section
> using elf helpers

Right, abg-elf-helpers.h does have find_section_by_name.  That can be
used to look for the debug info, I guess.  However, we also need to
support finding the debug info when it's split out into a different
place, like when it's packaged in a separate debug-info package.  Today,
abg-dwarf-reader.cc uses dwfl (dwarf front-end library, I believe) to do
this, as dwfl knows how to find the DWARF debug info, wherever it is.

You can see how this is done in read_context::load_debug_info(), in
abg-dwarf-reader.cc, around line 2654.  Look for the comment "Look for
split debuginfo files".  Basically, dwfl_module_getdwarf returns a
pointer to the debug info it's found, if it has found one.  I think we
should split this logic out to make it re-usable somehow.

If you think this is worthwhile, I can think of splitting it out and
stick it into elf-helpers, maybe?


> and it can be used in `load_corpus_and_write_abixml'
> implementing a similar algorithm as with when we are processing the Kernel,
> looking for DWARF information, and if it is not present then, test if
> `.ctf' section is in ELF file then extract it using CTF reader,
> to avoid duplication use of:
>
> abigail::ctf_reader::read_context_sptr ctxt
> 		= abigail::ctf_reader::create_read_context(opts.in_file_path,
> 							   opts.prepared_di_root_paths,
> 							   env.get());
>
> One for `opts.use_ctf' and other one when `STATUS_DEBUG_INFO_NOT_FOUND' is returned.
> WDYT?

Yes, along with the testing for the presence of DWARF debug info, that
might be useful, indeed.

[...]

>> But then, it's here that we are going to inspect c1_status to see if
>> loading DWARF failed.  If it failed, then we'll try to load CTF.  So,
>> here is the change I am adding to the process of loading the corpus c1:
>>
>>
>> @@ -1205,6 +1208,36 @@ main(int argc, char* argv[])
>>                   set_suppressions(*ctxt, opts);
>>                   abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
>>                   c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
>> +
>> +#ifdef WITH_CTF
>> +		if (// We were not instructed to use CTF ...
>> +		    !opts.use_ctf
>
> This is always true, because we are in the else block of `opts.use_ctf'.

Right.

>
>> +		    // ... and yet, no debug info was found ...
>> +		    && (c1_status & STATUS_DEBUG_INFO_NOT_FOUND)
>> +		    // ... but we found ELF symbols ...
>> +		    && !(c1_status & STATUS_NO_SYMBOLS_FOUND))
>> +		  {
>> +		    string basenam, dirnam;
>> +		    base_name(opts.file1, basenam);
>> +		    dir_name(opts.file1, dirnam);
>> +		    // ... the input file seems to contain CTF
>> +		    // archive, so let's try to see if the file
>> +		    // contains a CTF archive, who knows ...
>> +		    if (dir_contains_ctf_archive(dirnam, basenam))
>
> Non-kernel binaries contains `.ctf' section instead of `ctfa' file,
> so I can implement a `file_contains_ctf_section' function to test if
> it is a valid input file for CTF reader.

Great, thanks.

OK, I'll look into trying to put together some facility to look for the
presence of DWARF debug info, so tools can decide ahead of time what
front-end to use.

[...]

Cheers,

-- 
		Dodji

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

* Re: [PATCH] CTF as a fallback when no DWARF debug info is present
  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
  1 sibling, 1 reply; 17+ messages in thread
From: Dodji Seketeli @ 2022-10-06 14:12 UTC (permalink / raw)
  To: Guillermo E. Martinez; +Cc: Guillermo E. Martinez via Libabigail

Hey again Guillermo,

So, even before you sent the patch, I was "playing" with the idea of
re-organizing the code of the readers to make front-ends/readers be
first class citizens in libabigail.

The idea is to have all the front-ends share/implement an abstract
interface: the Front End Interface, named abigail::fe_iface.  So there
would be abigail::elf_reader::reader, abigail::dwarf_reader::reader and
abigail::ctf_reader::reader and abigtail::abixml_reader::reader
front-ends, all implementing the abigail::fe_iface.  They would all have
to grok their intended input, build the IR as a result and pass it to
the middle-end.

Most of the craft of analyzing the ELF part would be of course in
located in the abigail::elf_reader::reader type.

The abigail::{dwarf,ctf}_reader::reader types would just have to use the
elf_reader::reader type to handle ELF stuff.

An example of what that would look like is in the
"users/dodji/front-end" branch at
https://sourceware.org/git/?p=libabigail.git;a=shortlog;h=refs/heads/users/dodji/front-end.

The interface of the new elf-reader type is at
https://sourceware.org/git/?p=libabigail.git;a=blob;f=include/abg-elf-reader.h;hb=refs/heads/users/dodji/front-end.

The abigail::fe_iface interface it implements is at
https://sourceware.org/git/?p=libabigail.git;a=blob;f=include/abg-fe-iface.h;hb=refs/heads/users/dodji/front-end.

It's not yet documented, but after the discussion we had on your patch,
I tried to implement a helper function
abigail::tools_utils::file_has_dwarf_debug_info() using the new
abigail::elf_reader::reader type.

You can see it at
https://sourceware.org/git/?p=libabigail.git;a=blob;f=src/abg-tools-utils.cc;hb=refs/heads/users/dodji/front-end#l423

So, that function file_has_dwarf_debug_info() can be used to determine
if an ELF file has debug info (even taking into account split debug
information).  Based on that information, the tool could chose the right
front-end to use.

This is still work-in-progress, but the branch passes "make distcheck",
for what it's worth.

If you are interested, maybe you could base the subsequent versions of
your patch on this branch?  What do you think?

In any case, I'll keep exploring this topic on that branch and I'll send
a message to the list a bit later to present it a little bit further.

Cheers,

-- 
		Dodji

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

* Re: [PATCH] CTF as a fallback when no DWARF debug info is present
  2022-10-06 19:53       ` Guillermo Martinez
@ 2022-10-06 19:50         ` Guillermo E. Martinez
  2022-10-07 13:38         ` Dodji Seketeli
  1 sibling, 0 replies; 17+ messages in thread
From: Guillermo E. Martinez @ 2022-10-06 19:50 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: Guillermo E. Martinez via Libabigail



On 10/6/22 02:42, Dodji Seketeli wrote:
> Hello Guillermo,
> 

Hello Dodji,

Thanks for your comments!

> "Guillermo E. Martinez" <guillermo.e.martinez@oracle.com> a écrit:
> 
> [...]
> 
>>> I have also introduced a new function called
>>> tools_utils::dir_contains_ctf_archive to look for a file that ends with
>>> ".ctfa".  This abstracts away the search for "vmlinux.ctfa" as I wasn't
>>> sure if those archives could exist for normal (non-kernel) binaries as
>>> well:
>>
>> Ohh, perfect!, I'll use it in CTF reader to located the Linux archive file.
> 
> ACK.
> 
> [...]
> 
>>>       @@ -2525,8 +2542,12 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
>>>        /// @param t time to trace time spent in each step.
>>>        ///
>>>        /// @param env the environment to create the corpus_group in.
>>>       -static void
>>>       -maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>>>       +///
>>>       +/// @return the status of the loading.  If it's
>>>       +/// abigail::elf_reader::STATUS_UNKNOWN, then it means nothing was
>>>       +/// done, meaning the function got out early.
>>>       +static abigail::elf_reader::status
>>>       +maybe_load_vmlinux_dwarf_corpus(corpus::origin&     origin,
>>>                                        corpus_group_sptr&  group,
>>>                                        const string&       vmlinux,
>>>                                        vector<string>&     modules,
>>>       @@ -2539,10 +2560,11 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>>>                                        timer&              t,
>>>                                        environment_sptr&   env)
>>>        {
>>>       +  abigail::elf_reader::status status = abigail::elf_reader::STATUS_UNKNOWN;
>>>       +
>>>          if (!(origin & corpus::DWARF_ORIGIN))
>>>       -    return;
>>>       +    return status;
>>>
>>>       -  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
>>>          dwarf_reader::read_context_sptr ctxt;
>>>          ctxt =
>>>           dwarf_reader::create_read_context(vmlinux, di_roots, env.get(),
>>>       @@ -2569,6 +2591,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>>>             << vmlinux << "' ...\n" << std::flush;
>>>
>>>          // Read the vmlinux corpus and add it to the group.
>>>       +  status = abigail::elf_reader::STATUS_OK;
>>>          t.start();
>>>          read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
>>>          t.stop();
>>>       @@ -2579,7 +2602,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>>>             << t << "\n";
>>>
>>
>> At this point if `vmlinux' file doesn't have DWARF information, the `status'
>> returned by `maybe_load_vmlinux_dwarf_corpus' will set the bit field
>> `STATUS_DEBUG_INFO_NOT_FOUND', but it is not verified here, and since vmlinux
>> corpus was already added into the group in `read_debug_info_into_corpus'
>> function, it continues processing modules without the main corpus information,
> 
> I see.  You are right.  Yes, the debug info is not found in vmlinux and yet the
> whole thing continues, collecting just information from the ELF symbol
> table, basically, and from the modules.  Pretty useless, I guess.
> 
>> Is this the expected behaviour?
> 
> Hehe, no :-)
> 
> I guess maybe the caller should look for the .debug_info section in the
> vmlinux section (or for split debug info), prior to even calling
> maybe_load_vmlinux_dwarf_corpus.  If there is no debug info, then the
> function should proceed directly to calling
> maybe_load_vmlinux_ctf_corpus?  What do you think?
> 

Yes, it sounds good!!, just I would like to know your opinion about of what
will happen when neither DWARF nor CTF debug information is found, the current
behavior is to extract symbols information and compare them, so which symbol
information should I use DWARF::symtab or CTF::symtab?

And an additional use case is whether the tools `kmidiff', `abidiff' could
compare a DWARF IR with CTF IR? I exercised it with some libraries and binaries
using `abidiff' (finding a couple of problems in CTF reader (already fixed)
and three possible issues for DWARF, I will submit information and the test
cases about those) but in general seems to be work!, but before  to continue
I would like to know your thoughts.

> [...]
> 
>>> I have also introduced a new function called
>>> tools_utils::dir_contains_ctf_archive to look for a file that ends with
>>> ".ctfa".  This abstracts away the search for "vmlinux.ctfa" as I wasn't
>>> sure if those archives could exist for normal (non-kernel) binaries as
>>> well:
>>
>> Ohh, perfect!, I'll use it in CTF reader to located the Linux archive file.
>> No. there is no `.ctfa' file for non-kernel binaries intead they have `.ctf'
>> section, I could implement a similary function to looks for `.ctf' section
>> using elf helpers
> 
> Right, abg-elf-helpers.h does have find_section_by_name.  That can be
> used to look for the debug info, I guess.  However, we also need to
> support finding the debug info when it's split out into a different
> place, like when it's packaged in a separate debug-info package.  Today,
> abg-dwarf-reader.cc uses dwfl (dwarf front-end library, I believe) to do
> this, as dwfl knows how to find the DWARF debug info, wherever it is.
> 

Ohh, your are right, I saw `find_alt_debug_info', and in case of CTF front-end
we don't use dwfl, it is done by `find_alt_debuginfo', reading directly the content
of `.gnu_debuglink' section, I'm not sure if CTF reader can use `find_alt_debug_info'
because it calls dwfl_* functions seems be DWARF specific. So I'll investigate.

> You can see how this is done in read_context::load_debug_info(), in
> abg-dwarf-reader.cc, around line 2654.  Look for the comment "Look for
> split debuginfo files".  Basically, dwfl_module_getdwarf returns a
> pointer to the debug info it's found, if it has found one.  I think we
> should split this logic out to make it re-usable somehow.
> 
> If you think this is worthwhile, I can think of splitting it out and
> stick it into elf-helpers, maybe?
> 

It will be really useful!, but I'm not sure `dwfl_module_getdwarf'
can operate in ELF without `.debug_*' sections.

> 
>> and it can be used in `load_corpus_and_write_abixml'
>> implementing a similar algorithm as with when we are processing the Kernel,
>> looking for DWARF information, and if it is not present then, test if
>> `.ctf' section is in ELF file then extract it using CTF reader,
>> to avoid duplication use of:
>>
>> abigail::ctf_reader::read_context_sptr ctxt
>> 		= abigail::ctf_reader::create_read_context(opts.in_file_path,
>> 							   opts.prepared_di_root_paths,
>> 							   env.get());
>>
>> One for `opts.use_ctf' and other one when `STATUS_DEBUG_INFO_NOT_FOUND' is returned.
>> WDYT?
> 
> Yes, along with the testing for the presence of DWARF debug info, that
> might be useful, indeed.
> 

Agree.

> [...]
> 
>>> But then, it's here that we are going to inspect c1_status to see if
>>> loading DWARF failed.  If it failed, then we'll try to load CTF.  So,
>>> here is the change I am adding to the process of loading the corpus c1:
>>>
>>>
>>> @@ -1205,6 +1208,36 @@ main(int argc, char* argv[])
>>>                    set_suppressions(*ctxt, opts);
>>>                    abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
>>>                    c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
>>> +
>>> +#ifdef WITH_CTF
>>> +		if (// We were not instructed to use CTF ...
>>> +		    !opts.use_ctf
>>
>> This is always true, because we are in the else block of `opts.use_ctf'.
> 
> Right.
> 
>>
>>> +		    // ... and yet, no debug info was found ...
>>> +		    && (c1_status & STATUS_DEBUG_INFO_NOT_FOUND)
>>> +		    // ... but we found ELF symbols ...
>>> +		    && !(c1_status & STATUS_NO_SYMBOLS_FOUND))
>>> +		  {
>>> +		    string basenam, dirnam;
>>> +		    base_name(opts.file1, basenam);
>>> +		    dir_name(opts.file1, dirnam);
>>> +		    // ... the input file seems to contain CTF
>>> +		    // archive, so let's try to see if the file
>>> +		    // contains a CTF archive, who knows ...
>>> +		    if (dir_contains_ctf_archive(dirnam, basenam))
>>
>> Non-kernel binaries contains `.ctf' section instead of `ctfa' file,
>> so I can implement a `file_contains_ctf_section' function to test if
>> it is a valid input file for CTF reader.
> 
> Great, thanks.
> 
> OK, I'll look into trying to put together some facility to look for the
> presence of DWARF debug info, so tools can decide ahead of time what
> front-end to use.
> 

Really nice!.

> [...]
> 
> Cheers,
> 

Regards,
guillermo

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

* Re: [PATCH] CTF as a fallback when no DWARF debug info is present
  2022-10-06  7:42     ` Dodji Seketeli
  2022-10-06 14:12       ` Dodji Seketeli
@ 2022-10-06 19:53       ` Guillermo Martinez
  2022-10-06 19:50         ` Guillermo E. Martinez
  2022-10-07 13:38         ` Dodji Seketeli
  1 sibling, 2 replies; 17+ messages in thread
From: Guillermo Martinez @ 2022-10-06 19:53 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: Guillermo E. Martinez via Libabigail



On 10/6/22 02:42, Dodji Seketeli wrote:
> Hello Guillermo,
> 

Hello Dodji,

Thanks for your comments!

> "Guillermo E. Martinez" <guillermo.e.martinez@oracle.com> a écrit:
> 
> [...]
> 
>>> I have also introduced a new function called
>>> tools_utils::dir_contains_ctf_archive to look for a file that ends with
>>> ".ctfa".  This abstracts away the search for "vmlinux.ctfa" as I wasn't
>>> sure if those archives could exist for normal (non-kernel) binaries as
>>> well:
>>
>> Ohh, perfect!, I'll use it in CTF reader to located the Linux archive file.
> 
> ACK.
> 
> [...]
> 
>>>       @@ -2525,8 +2542,12 @@ get_binary_paths_from_kernel_dist(const string&	dist_root,
>>>        /// @param t time to trace time spent in each step.
>>>        ///
>>>        /// @param env the environment to create the corpus_group in.
>>>       -static void
>>>       -maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>>>       +///
>>>       +/// @return the status of the loading.  If it's
>>>       +/// abigail::elf_reader::STATUS_UNKNOWN, then it means nothing was
>>>       +/// done, meaning the function got out early.
>>>       +static abigail::elf_reader::status
>>>       +maybe_load_vmlinux_dwarf_corpus(corpus::origin&     origin,
>>>                                        corpus_group_sptr&  group,
>>>                                        const string&       vmlinux,
>>>                                        vector<string>&     modules,
>>>       @@ -2539,10 +2560,11 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>>>                                        timer&              t,
>>>                                        environment_sptr&   env)
>>>        {
>>>       +  abigail::elf_reader::status status = abigail::elf_reader::STATUS_UNKNOWN;
>>>       +
>>>          if (!(origin & corpus::DWARF_ORIGIN))
>>>       -    return;
>>>       +    return status;
>>>
>>>       -  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
>>>          dwarf_reader::read_context_sptr ctxt;
>>>          ctxt =
>>>           dwarf_reader::create_read_context(vmlinux, di_roots, env.get(),
>>>       @@ -2569,6 +2591,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>>>             << vmlinux << "' ...\n" << std::flush;
>>>
>>>          // Read the vmlinux corpus and add it to the group.
>>>       +  status = abigail::elf_reader::STATUS_OK;
>>>          t.start();
>>>          read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
>>>          t.stop();
>>>       @@ -2579,7 +2602,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
>>>             << t << "\n";
>>>
>>
>> At this point if `vmlinux' file doesn't have DWARF information, the `status'
>> returned by `maybe_load_vmlinux_dwarf_corpus' will set the bit field
>> `STATUS_DEBUG_INFO_NOT_FOUND', but it is not verified here, and since vmlinux
>> corpus was already added into the group in `read_debug_info_into_corpus'
>> function, it continues processing modules without the main corpus information,
> 
> I see.  You are right.  Yes, the debug info is not found in vmlinux and yet the
> whole thing continues, collecting just information from the ELF symbol
> table, basically, and from the modules.  Pretty useless, I guess.
> 
>> Is this the expected behaviour?
> 
> Hehe, no :-)
> 
> I guess maybe the caller should look for the .debug_info section in the
> vmlinux section (or for split debug info), prior to even calling
> maybe_load_vmlinux_dwarf_corpus.  If there is no debug info, then the
> function should proceed directly to calling
> maybe_load_vmlinux_ctf_corpus?  What do you think?
> 

Yes, it sounds good!!, just I would like to know your opinion about of what
will happen when neither DWARF nor CTF debug information is found, the current
behavior is to extract symbols information and compare them, so which symbol
information should I use DWARF::symtab or CTF::symtab?

And an additional use case is whether the tools `kmidiff', `abidiff' could
compare a DWARF IR with CTF IR? I exercised it with some libraries and binaries
using `abidiff' (finding a couple of problems in CTF reader (already fixed)
and three possible issues for DWARF, I will submit information and the test
cases about those) but in general seems to be work!, but before  to continue
I would like to know your thoughts.

> [...]
> 
>>> I have also introduced a new function called
>>> tools_utils::dir_contains_ctf_archive to look for a file that ends with
>>> ".ctfa".  This abstracts away the search for "vmlinux.ctfa" as I wasn't
>>> sure if those archives could exist for normal (non-kernel) binaries as
>>> well:
>>
>> Ohh, perfect!, I'll use it in CTF reader to located the Linux archive file.
>> No. there is no `.ctfa' file for non-kernel binaries intead they have `.ctf'
>> section, I could implement a similary function to looks for `.ctf' section
>> using elf helpers
> 
> Right, abg-elf-helpers.h does have find_section_by_name.  That can be
> used to look for the debug info, I guess.  However, we also need to
> support finding the debug info when it's split out into a different
> place, like when it's packaged in a separate debug-info package.  Today,
> abg-dwarf-reader.cc uses dwfl (dwarf front-end library, I believe) to do
> this, as dwfl knows how to find the DWARF debug info, wherever it is.
> 

Ohh, your are right, I saw `find_alt_debug_info', and in case of CTF front-end
we don't use dwfl, it is done by `find_alt_debuginfo', reading directly the content
of `.gnu_debuglink' section, I'm not sure if CTF reader can use `find_alt_debug_info'
because it calls dwfl_* functions seems be DWARF specific. So I'll investigate.

> You can see how this is done in read_context::load_debug_info(), in
> abg-dwarf-reader.cc, around line 2654.  Look for the comment "Look for
> split debuginfo files".  Basically, dwfl_module_getdwarf returns a
> pointer to the debug info it's found, if it has found one.  I think we
> should split this logic out to make it re-usable somehow.
> 
> If you think this is worthwhile, I can think of splitting it out and
> stick it into elf-helpers, maybe?
> 

It will be really useful!, but I'm not sure `dwfl_module_getdwarf'
can operate in ELF without `.debug_*' sections.

> 
>> and it can be used in `load_corpus_and_write_abixml'
>> implementing a similar algorithm as with when we are processing the Kernel,
>> looking for DWARF information, and if it is not present then, test if
>> `.ctf' section is in ELF file then extract it using CTF reader,
>> to avoid duplication use of:
>>
>> abigail::ctf_reader::read_context_sptr ctxt
>> 		= abigail::ctf_reader::create_read_context(opts.in_file_path,
>> 							   opts.prepared_di_root_paths,
>> 							   env.get());
>>
>> One for `opts.use_ctf' and other one when `STATUS_DEBUG_INFO_NOT_FOUND' is returned.
>> WDYT?
> 
> Yes, along with the testing for the presence of DWARF debug info, that
> might be useful, indeed.
> 

Agree.

> [...]
> 
>>> But then, it's here that we are going to inspect c1_status to see if
>>> loading DWARF failed.  If it failed, then we'll try to load CTF.  So,
>>> here is the change I am adding to the process of loading the corpus c1:
>>>
>>>
>>> @@ -1205,6 +1208,36 @@ main(int argc, char* argv[])
>>>                    set_suppressions(*ctxt, opts);
>>>                    abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
>>>                    c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
>>> +
>>> +#ifdef WITH_CTF
>>> +		if (// We were not instructed to use CTF ...
>>> +		    !opts.use_ctf
>>
>> This is always true, because we are in the else block of `opts.use_ctf'.
> 
> Right.
> 
>>
>>> +		    // ... and yet, no debug info was found ...
>>> +		    && (c1_status & STATUS_DEBUG_INFO_NOT_FOUND)
>>> +		    // ... but we found ELF symbols ...
>>> +		    && !(c1_status & STATUS_NO_SYMBOLS_FOUND))
>>> +		  {
>>> +		    string basenam, dirnam;
>>> +		    base_name(opts.file1, basenam);
>>> +		    dir_name(opts.file1, dirnam);
>>> +		    // ... the input file seems to contain CTF
>>> +		    // archive, so let's try to see if the file
>>> +		    // contains a CTF archive, who knows ...
>>> +		    if (dir_contains_ctf_archive(dirnam, basenam))
>>
>> Non-kernel binaries contains `.ctf' section instead of `ctfa' file,
>> so I can implement a `file_contains_ctf_section' function to test if
>> it is a valid input file for CTF reader.
> 
> Great, thanks.
> 
> OK, I'll look into trying to put together some facility to look for the
> presence of DWARF debug info, so tools can decide ahead of time what
> front-end to use.
> 

Really nice!.

> [...]
> 
> Cheers,
> 

Regards,
guillermo

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

* Re: [PATCH] CTF as a fallback when no DWARF debug info is present
  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
  1 sibling, 1 reply; 17+ messages in thread
From: Dodji Seketeli @ 2022-10-07 13:38 UTC (permalink / raw)
  To: Guillermo Martinez; +Cc: Guillermo E. Martinez via Libabigail

Hello Guillermo,

Guillermo Martinez <guillermo.e.martinez@oracle.com> a écrit:

> Yes, it sounds good!!, just I would like to know your opinion about of what
> will happen when neither DWARF nor CTF debug information is found, the current
> behavior is to extract symbols information and compare them, so which symbol
> information should I use DWARF::symtab or CTF::symtab?

In the new branch users/dodji/front-end, both the CTF and DWARF readers
are going to be (re)using the same ELF Reader type.  That was one of the
goals of that branch.  And so the symtab object is going to come from
there, so which ever you chose right now, it won't matter in the end
when the "front-end" branch is merged into master.

> And an additional use case is whether the tools `kmidiff', `abidiff' could
> compare a DWARF IR with CTF IR?

Why not?  We compare ABIXML againt DWARF or CTF already.  So why not
trying to compare CTF against DWARF, see what breaks and then try to fix
it? :-)

> I exercised it with some libraries and binaries using `abidiff'
> (finding a couple of problems in CTF reader (already fixed) and three
> possible issues for DWARF, I will submit information and the test
> cases about those) but in general seems to be work!, but before to
> continue I would like to know your thoughts.

There you go \o/  I think it's a good idea.

[...]

>> Right, abg-elf-helpers.h does have find_section_by_name.  That can be
>> used to look for the debug info, I guess.  However, we also need to
>> support finding the debug info when it's split out into a different
>> place, like when it's packaged in a separate debug-info package.  Today,
>> abg-dwarf-reader.cc uses dwfl (dwarf front-end library, I believe) to do
>> this, as dwfl knows how to find the DWARF debug info, wherever it is.
>> 
>
> Ohh, your are right, I saw `find_alt_debug_info', and in case of CTF front-end
> we don't use dwfl, it is done by `find_alt_debuginfo', reading directly the content
> of `.gnu_debuglink' section, I'm not sure if CTF reader can use `find_alt_debug_info'
> because it calls dwfl_* functions seems be DWARF specific. So I'll investigate.
>
>> You can see how this is done in read_context::load_debug_info(), in
>> abg-dwarf-reader.cc, around line 2654.  Look for the comment "Look for
>> split debuginfo files".  Basically, dwfl_module_getdwarf returns a
>> pointer to the debug info it's found, if it has found one.  I think we
>> should split this logic out to make it re-usable somehow.
>> 
>> If you think this is worthwhile, I can think of splitting it out and
>> stick it into elf-helpers, maybe?
>> 
>
> It will be really useful!, but I'm not sure `dwfl_module_getdwarf'
> can operate in ELF without `.debug_*' sections.

In the "front-end" branch, I've put the new file_has_dwarf_debug_info
for you to see at
https://sourceware.org/git/?p=libabigail.git;a=blob;f=src/abg-tools-utils.cc;hb=refs/heads/users/dodji/front-end#l423

Maybe the new elf_reader::reader type (in the new src/abg-elf-reader.cc
file in the "front-end" branch) should grow a new
elf_reader::reader::ctf_debug_info() member function that returns a
pointer to the CTF object, just like what
elf_reader::reader::dwarf_debug_info does?  That function would look
into the .ctf section, or use file_alt_debuginfo to locate the
.gnu_debuglink section and use its content to locate the split debuginfo
file.

I think it's fairly doable.  What do you think?

[...]

Cheers,

-- 
		Dodji

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

* Re: [PATCH] CTF as a fallback when no DWARF debug info is present
  2022-10-06 14:12       ` Dodji Seketeli
@ 2022-10-07 14:13         ` Guillermo E. Martinez
  0 siblings, 0 replies; 17+ messages in thread
From: Guillermo E. Martinez @ 2022-10-07 14:13 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: Guillermo E. Martinez via Libabigail



On 10/6/22 09:12, Dodji Seketeli wrote:
> Hey again Guillermo,
> 
> So, even before you sent the patch, I was "playing" with the idea of
> re-organizing the code of the readers to make front-ends/readers be
> first class citizens in libabigail.
> 

Ohh, cool.

> The idea is to have all the front-ends share/implement an abstract
> interface: the Front End Interface, named abigail::fe_iface.  So there
> would be abigail::elf_reader::reader, abigail::dwarf_reader::reader and
> abigail::ctf_reader::reader and abigtail::abixml_reader::reader
> front-ends, all implementing the abigail::fe_iface.  They would all have
> to grok their intended input, build the IR as a result and pass it to
> the middle-end.
> 

OK, perfect!.

> Most of the craft of analyzing the ELF part would be of course in
> located in the abigail::elf_reader::reader type.
> 
> The abigail::{dwarf,ctf}_reader::reader types would just have to use the
> elf_reader::reader type to handle ELF stuff.
> 

OK.

> An example of what that would look like is in the
> "users/dodji/front-end" branch at
> https://sourceware.org/git/?p=libabigail.git;a=shortlog;h=refs/heads/users/dodji/front-end.
> 
> The interface of the new elf-reader type is at
> https://sourceware.org/git/?p=libabigail.git;a=blob;f=include/abg-elf-reader.h;hb=refs/heads/users/dodji/front-end.
> 
> The abigail::fe_iface interface it implements is at
> https://sourceware.org/git/?p=libabigail.git;a=blob;f=include/abg-fe-iface.h;hb=refs/heads/users/dodji/front-end.
> 
> It's not yet documented, but after the discussion we had on your patch,
> I tried to implement a helper function
> abigail::tools_utils::file_has_dwarf_debug_info() using the new
> abigail::elf_reader::reader type.
> 
> You can see it at
> https://sourceware.org/git/?p=libabigail.git;a=blob;f=src/abg-tools-utils.cc;hb=refs/heads/users/dodji/front-end#l423
> 
> So, that function file_has_dwarf_debug_info() can be used to determine
> if an ELF file has debug info (even taking into account split debug
> information).  Based on that information, the tool could chose the right
> front-end to use.
> 

Perfect!.

> This is still work-in-progress, but the branch passes "make distcheck",
> for what it's worth.
> 
> If you are interested, maybe you could base the subsequent versions of
> your patch on this branch?  What do you think?
> 

Totally agree.

> In any case, I'll keep exploring this topic on that branch and I'll send
> a message to the list a bit later to present it a little bit further.
> 

Thanks!.

> Cheers,
> 

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

* Re: [PATCH] CTF as a fallback when no DWARF debug info is present
  2022-10-07 13:38         ` Dodji Seketeli
@ 2022-10-07 16:04           ` Ben Woodard
  0 siblings, 0 replies; 17+ messages in thread
From: Ben Woodard @ 2022-10-07 16:04 UTC (permalink / raw)
  To: Dodji Seketeli, Guillermo Martinez; +Cc: Guillermo E. Martinez via Libabigail


On 10/7/22 06:38, Dodji Seketeli wrote:
> Hello Guillermo,
>
> Guillermo Martinez <guillermo.e.martinez@oracle.com> a écrit:
>
>> Yes, it sounds good!!, just I would like to know your opinion about of what
>> will happen when neither DWARF nor CTF debug information is found, the current
>> behavior is to extract symbols information and compare them, so which symbol
>> information should I use DWARF::symtab or CTF::symtab?
> In the new branch users/dodji/front-end, both the CTF and DWARF readers
> are going to be (re)using the same ELF Reader type.  That was one of the
> goals of that branch.  And so the symtab object is going to come from
> there, so which ever you chose right now, it won't matter in the end
> when the "front-end" branch is merged into master.
>
>> And an additional use case is whether the tools `kmidiff', `abidiff' could
>> compare a DWARF IR with CTF IR?
> Why not?  We compare ABIXML againt DWARF or CTF already.  So why not
> trying to compare CTF against DWARF, see what breaks and then try to fix
> it? :-)
I'm strongly in favor of this.
>
>> I exercised it with some libraries and binaries using `abidiff'
>> (finding a couple of problems in CTF reader (already fixed) and three
>> possible issues for DWARF, I will submit information and the test
>> cases about those) but in general seems to be work!, but before to
>> continue I would like to know your thoughts.
> There you go \o/  I think it's a good idea.
>
> [...]
>
>>> Right, abg-elf-helpers.h does have find_section_by_name.  That can be
>>> used to look for the debug info, I guess.  However, we also need to
>>> support finding the debug info when it's split out into a different
>>> place, like when it's packaged in a separate debug-info package.  Today,
>>> abg-dwarf-reader.cc uses dwfl (dwarf front-end library, I believe) to do
>>> this, as dwfl knows how to find the DWARF debug info, wherever it is.
>>>
>> Ohh, your are right, I saw `find_alt_debug_info', and in case of CTF front-end
>> we don't use dwfl, it is done by `find_alt_debuginfo', reading directly the content
>> of `.gnu_debuglink' section, I'm not sure if CTF reader can use `find_alt_debug_info'
>> because it calls dwfl_* functions seems be DWARF specific. So I'll investigate.
>>
>>> You can see how this is done in read_context::load_debug_info(), in
>>> abg-dwarf-reader.cc, around line 2654.  Look for the comment "Look for
>>> split debuginfo files".  Basically, dwfl_module_getdwarf returns a
>>> pointer to the debug info it's found, if it has found one.  I think we
>>> should split this logic out to make it re-usable somehow.
>>>
>>> If you think this is worthwhile, I can think of splitting it out and
>>> stick it into elf-helpers, maybe?
>>>
>> It will be really useful!, but I'm not sure `dwfl_module_getdwarf'
>> can operate in ELF without `.debug_*' sections.
> In the "front-end" branch, I've put the new file_has_dwarf_debug_info
> for you to see at
> https://sourceware.org/git/?p=libabigail.git;a=blob;f=src/abg-tools-utils.cc;hb=refs/heads/users/dodji/front-end#l423
>
> Maybe the new elf_reader::reader type (in the new src/abg-elf-reader.cc
> file in the "front-end" branch) should grow a new
> elf_reader::reader::ctf_debug_info() member function that returns a
> pointer to the CTF object, just like what
> elf_reader::reader::dwarf_debug_info does?  That function would look
> into the .ctf section, or use file_alt_debuginfo to locate the
> .gnu_debuglink section and use its content to locate the split debuginfo
> file.
>
> I think it's fairly doable.  What do you think?
>
> [...]
>
> Cheers,
>


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

* [PATCHv2] ELF based front-end readers fallback feature
  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-11-15 20:13 ` Guillermo E. Martinez
  2022-11-21 18:51   ` [PATCHv3] " Guillermo E. Martinez
  1 sibling, 1 reply; 17+ messages in thread
From: Guillermo E. Martinez @ 2022-11-15 20:13 UTC (permalink / raw)
  To: libabigail; +Cc: Guillermo E. Martinez

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

Changes from v1:
   * Adjust previous implementation alignment with commit:
     9b4a6e9e304bf8a4f21e44a497a4379826b4b1ae,

     in branch:
        users/dodji/front-end

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'.
	* 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                         | 196 ++++++------
 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                        |  91 ++++--
 tests/test-read-dwarf.cc                      | 119 ++++++--
 tools/abidiff.cc                              |  44 ++-
 tools/abidw.cc                                |  26 +-
 tools/abipkgdiff.cc                           |  43 ++-
 26 files changed, 574 insertions(+), 387 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..9950de57 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,30 @@ 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)
   {
     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 +353,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 +403,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;
@@ -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;
 	}
@@ -642,7 +637,7 @@ public:
     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 +659,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 +691,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 +713,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 +720,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);
@@ -782,7 +774,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 +781,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 +864,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 +871,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.  */
@@ -964,20 +953,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;
@@ -1024,17 +1011,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 +1069,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 +1076,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 +1114,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 +1122,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 +1129,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 +1165,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 +1173,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;
@@ -1284,18 +1263,16 @@ 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);
@@ -1337,8 +1314,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,11 +1321,11 @@ 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)
@@ -1383,8 +1358,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 +1365,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 +1403,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..14e63ef0 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,6 +333,17 @@ 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}
@@ -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..2395fcbc 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,7 +548,23 @@ 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}
 };
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


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

* [PATCHv3] ELF based front-end readers fallback feature
  2022-11-15 20:13 ` [PATCHv2] ELF based front-end readers fallback feature Guillermo E. Martinez
@ 2022-11-21 18:51   ` Guillermo E. Martinez
  2022-11-22 14:19     ` Dodji Seketeli
  2022-11-22 16:00     ` [PATCH v4] " Guillermo E. Martinez
  0 siblings, 2 replies; 17+ messages in thread
From: Guillermo E. Martinez @ 2022-11-21 18:51 UTC (permalink / raw)
  To: libabigail; +Cc: Guillermo E. Martinez

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

Changes from v2:
   * Fix warnings generated by using -Wall -Wextra -Werror flags.

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-dwarf/test-fallback.abi  |   9 +
 tests/data/test-read-dwarf/test-fallback.c    |   8 +
 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 ++-
 24 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-dwarf/test-fallback.abi
 create mode 100644 tests/data/test-read-dwarf/test-fallback.c

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-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/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


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

* Re: [PATCHv3] ELF based front-end readers fallback feature
  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     ` [PATCH v4] " Guillermo E. Martinez
  1 sibling, 1 reply; 17+ messages in thread
From: Dodji Seketeli @ 2022-11-22 14:19 UTC (permalink / raw)
  To: Guillermo E. Martinez via Libabigail; +Cc: Guillermo E. Martinez

Hello Guillermo,

"Guillermo E. Martinez via Libabigail" <libabigail@sourceware.org> a
écrit:

[...]

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

It looks like the patch lacks the file
tests/data/test-read-dwarf/test-fallback.o.  Here is what I am getting
when I do "make distcheck-fast":

make[7]: *** No rule to make target 'test-read-dwarf/test-fallback.o', needed by 'distdir-am'.  Stop.

[...]

Cheers,

-- 
		Dodji

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

* [PATCH v4] ELF based front-end readers fallback feature
  2022-11-21 18:51   ` [PATCHv3] " Guillermo E. Martinez
  2022-11-22 14:19     ` Dodji Seketeli
@ 2022-11-22 16:00     ` Guillermo E. Martinez
  2022-11-28 15:56       ` Dodji Seketeli
  1 sibling, 1 reply; 17+ messages in thread
From: Guillermo E. Martinez @ 2022-11-22 16:00 UTC (permalink / raw)
  To: libabigail; +Cc: Guillermo E. Martinez

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


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

* Re: [PATCHv3] ELF based front-end readers fallback feature
  2022-11-22 14:19     ` Dodji Seketeli
@ 2022-11-22 16:02       ` Guillermo E. Martinez
  0 siblings, 0 replies; 17+ messages in thread
From: Guillermo E. Martinez @ 2022-11-22 16:02 UTC (permalink / raw)
  To: Dodji Seketeli, Guillermo E. Martinez via Libabigail



On 11/22/22 08:19, Dodji Seketeli wrote:
> Hello Guillermo,
> 

Hello Dodji,

> "Guillermo E. Martinez via Libabigail" <libabigail@sourceware.org> a
> écrit:
> 
> [...]
> 
>> 	* 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.
> 
> It looks like the patch lacks the file
> tests/data/test-read-dwarf/test-fallback.o.  Here is what I am getting
> when I do "make distcheck-fast":
> 

Uppss, my fault, I forget add -f to `git add'. I'll send v4.

> make[7]: *** No rule to make target 'test-read-dwarf/test-fallback.o', needed by 'distdir-am'.  Stop.
> 
> [...]
> 
> Cheers,
> 

Thanks,
guillermo

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

* Re: [PATCH v4] ELF based front-end readers fallback feature
  2022-11-22 16:00     ` [PATCH v4] " Guillermo E. Martinez
@ 2022-11-28 15:56       ` Dodji Seketeli
  2022-11-28 21:59         ` Guillermo E. Martinez
  0 siblings, 1 reply; 17+ messages in thread
From: Dodji Seketeli @ 2022-11-28 15:56 UTC (permalink / raw)
  To: Guillermo E. Martinez via Libabigail; +Cc: Guillermo E. Martinez

Hello Guillermo,

Many thanks for the update!  The patch looks good to me.

I have amended it somewhat and applied the result to the master branch.

Please find below my comments.

"Guillermo E. Martinez via Libabigail" <libabigail@sourceware.org> a
écrit:

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

I have slightly amended this part of the commit log.  You'll see the
resulting patch at the very end of this message.

[...]

> 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

[...]


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

I have slightly amended the comment here to make it read like this:

+	// Not finding any debug info so far is expected if we are
+	// 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))

the STATUS_DEBUG_INFO_NOT_FOUND bit cannot be set here because you have
unset it above by doing:

> +        status &= static_cast<abigail::fe_iface::status>
> +                    (~STATUS_DEBUG_INFO_NOT_FOUND);

So I have changed that condition to make it read:

+    if ((status & STATUS_NO_SYMBOLS_FOUND)
+	|| !(status & STATUS_OK))

[...]


> 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

[...]


>  
> +bool
> +reader::has_dwarf_debug_info() const

I have added a doxygen comment to this function.

> +{return ((priv_->dwarf_handle != nullptr)
> +	  || (priv_->alt_dwarf_handle != nullptr));}
> +
> +bool
> +reader::has_ctf_debug_info() const

Likewise.

> +{return (priv_->ctf_section != nullptr);}
> +

[...]

> diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
> index 8898ef97..0a523b87 100644

[...]

> 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,

Rather than adding a boolean here, I have added a parameter
'corpus::origin requested_fe_kind'.  This is basically the kind of
front-end requested by the user when invoking the tool.  For instance,
if --ctf is provided on the command line, requested_fe_kind should be
set to corpus::CTF_ORIGIN.  If nothing is provided on the command line,
either requested_fe_kind could be set to either
corpus::ARTIFICIAL_ORIGIN or corpus::DWARF_ORIGIN.  When we have another
kind of front-end tomorrow, requested_fe_kind will still be able to be
used because that new front-end is likely to be for a new kind
corpus::origin.  So, I think that doing this is a more generic solution.

> +			     bool show_all_types,
> +			     bool linux_kernel_mode = false);
>  
>  }// end namespace tools_utils
>  

> --- a/src/abg-tools-utils.cc
> +++ b/src/abg-tools-utils.cc
> @@ -405,6 +405,23 @@ is_regular_file(const string& path)
>    return false;
>  }

[...]

> @@ -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)

Following my comment above about the declaration of this function, I
have updated its definition here.

Near the end of this message, I'll paste my changes against the tree
containing your patch, so that you can see clearly the changes I've made
to create_best_elf_based_reader and to all the other related parts of
the patch.  But right now, please find the hunk I have come up with
about this specific location of the source code:

    -/// Create the best elf based reader (or front-end), given an ELF file.
    +/// Create the best elf based reader (or front-end), given an ELF
    +/// file.
    +///
    +/// This function looks into the ELF file; depending on the kind of
    +/// debug info it contains and on the request of the user, the "best"
    +/// front-end is created.
     ///
    -/// This function looks into the ELF file.  If it contains DWARF debug
    -/// 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.
    +/// If the user requested the use of the CTF front-end, then, if the
    +/// file contains CTF debug info, the CTF front-end is created,
    +/// assuming libabigail is built with CTF support.
     ///
    -/// By other hand, it selects the DWARF front-end when @ref use_ctf is
    -/// true but ELF file doesn't have CTF debug information.
    +/// If the binary ONLY has CTF debug info, then CTF front-end is
    +/// created, even if the user hasn't explicitly requested the creation
    +/// of the CTF front-end.
     ///
    -/// Otherwise, if the file contains no debug info or if the king of
    -/// debug info is not yet recognized, a DWARF or CTF  Reader front-end is
    -/// created and returned depending of @ref use_ctf parameter.
    +/// Otherwise, by default, the DWARF front-end is created.
     ///
     /// @param elf_file_path a path to the ELF file to consider
     ///
    @@ -2825,7 +2824,10 @@ 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 requested_fe_kind the kind of front-end specifically
    +/// requested by the user. At the moment, only the CTF front-end can
    +/// be requested, using the "--ctf" command line option on some tools
    +/// using the library.
     ///
     /// @param show_all_types option to be passed to elf based readers.
     ///
    @@ -2837,7 +2839,7 @@ elf_based_reader_sptr
     create_best_elf_based_reader(const string& elf_file_path,
                                 const vector<char**>& debug_info_root_paths,
                                 environment& env,
    -			     bool use_ctf,
    +			     corpus::origin requested_fe_kind,
                                 bool show_all_types,
                                 bool linux_kernel_mode)
     {
    @@ -2845,41 +2847,36 @@ create_best_elf_based_reader(const string& elf_file_path,
       if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
         return result;

    +  if (requested_fe_kind & corpus::CTF_ORIGIN)
    +    {
     #ifdef WITH_CTF
    -  if (!use_ctf)
    +      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);
    +#endif
    +    }
    +  else
         {
    +      // The user hasn't formally requested the use of the CTF front-end.
    +#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))
    +	// The file has CTF debug info and no DWARF, let's use the CTF
    +	// front end even if it wasn't formally requested by the user.
    +	result = ctf::create_reader(elf_file_path, debug_info_root_paths, env);
     #endif
    +    }
    +
    +  if (!result)
    +    {
    +      // This is the default case.  At worst, the DWARF reader knows
    +      // how to handle just ELF data for the case where there is no
    +      // DWARF debug info present.
           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 = 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;
     }

[...]

I have adjusted the rest of the code accordingly.

Please find below the diff of my changed related to
create_best_elf_based_reader and to other related parts.

--------------------------->8<------------------------------------------
diff --git a/include/abg-tools-utils.h b/include/abg-tools-utils.h
index 13d6ad75..3d7f0d23 100644
--- a/include/abg-tools-utils.h
+++ b/include/abg-tools-utils.h
@@ -317,13 +317,13 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 					  suppr::suppressions_type&	supprs,
 					  bool				verbose,
 					  environment&			env,
-					  corpus::origin	origin = corpus::DWARF_ORIGIN);
+					  corpus::origin	requested_fe_kind = corpus::DWARF_ORIGIN);
 
 elf_based_reader_sptr
 create_best_elf_based_reader(const string& elf_file_path,
 			     const vector<char**>& debug_info_root_paths,
 			     environment& env,
-			     bool use_ctf,
+			     corpus::origin requested_debug_info_kind,
 			     bool show_all_types,
 			     bool linux_kernel_mode = false);
 
diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
index 0a523b87..b089b69c 100644
--- a/src/abg-tools-utils.cc
+++ b/src/abg-tools-utils.cc
@@ -2755,7 +2755,7 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 					  suppressions_type&	supprs,
 					  bool			verbose,
 					  environment&		env,
-					  corpus::origin	origin)
+					  corpus::origin	requested_fe_kind)
 {
   string vmlinux = vmlinux_path;
   corpus_group_sptr group;
@@ -2787,11 +2787,7 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
         create_best_elf_based_reader(vmlinux,
                                      di_roots,
                                      env,
-#ifdef WITH_CTF
-                                     origin & corpus::CTF_ORIGIN,
-#else
-                                     false,
-#endif
+				     requested_fe_kind,
                                      /*read_all_types=*/false,
                                      /*linux_kernel_mode=*/true);
       ABG_ASSERT(reader);
@@ -2804,19 +2800,22 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
   return group;
 }
 
-/// Create the best elf based reader (or front-end), given an ELF file.
+/// Create the best elf based reader (or front-end), given an ELF
+/// file.
+///
+/// This function looks into the ELF file; depending on the kind of
+/// debug info it contains and on the request of the user, the "best"
+/// front-end is created.
 ///
-/// This function looks into the ELF file.  If it contains DWARF debug
-/// 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.
+/// If the user requested the use of the CTF front-end, then, if the
+/// file contains CTF debug info, the CTF front-end is created,
+/// assuming libabigail is built with CTF support.
 ///
-/// By other hand, it selects the DWARF front-end when @ref use_ctf is
-/// true but ELF file doesn't have CTF debug information.
+/// If the binary ONLY has CTF debug info, then CTF front-end is
+/// created, even if the user hasn't explicitly requested the creation
+/// of the CTF front-end.
 ///
-/// Otherwise, if the file contains no debug info or if the king of
-/// debug info is not yet recognized, a DWARF or CTF  Reader front-end is
-/// created and returned depending of @ref use_ctf parameter.
+/// Otherwise, by default, the DWARF front-end is created.
 ///
 /// @param elf_file_path a path to the ELF file to consider
 ///
@@ -2825,7 +2824,10 @@ 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 requested_fe_kind the kind of front-end specifically
+/// requested by the user. At the moment, only the CTF front-end can
+/// be requested, using the "--ctf" command line option on some tools
+/// using the library.
 ///
 /// @param show_all_types option to be passed to elf based readers.
 ///
@@ -2837,7 +2839,7 @@ elf_based_reader_sptr
 create_best_elf_based_reader(const string& elf_file_path,
 			     const vector<char**>& debug_info_root_paths,
 			     environment& env,
-			     bool use_ctf,
+			     corpus::origin requested_fe_kind,
 			     bool show_all_types,
 			     bool linux_kernel_mode)
 {
@@ -2845,41 +2847,36 @@ create_best_elf_based_reader(const string& elf_file_path,
   if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
     return result;
 
+  if (requested_fe_kind & corpus::CTF_ORIGIN)
+    {
 #ifdef WITH_CTF
-  if (!use_ctf)
+      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);
+#endif
+    }
+  else
     {
+      // The user hasn't formally requested the use of the CTF front-end.
+#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))
+	// The file has CTF debug info and no DWARF, let's use the CTF
+	// front end even if it wasn't formally requested by the user.
+	result = ctf::create_reader(elf_file_path, debug_info_root_paths, env);
 #endif
+    }
+
+  if (!result)
+    {
+      // This is the default case.  At worst, the DWARF reader knows
+      // how to handle just ELF data for the case where there is no
+      // DWARF debug info present.
       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 = 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/tools/abidiff.cc b/tools/abidiff.cc
index 6cd948bf..5ffe47a3 100644
--- a/tools/abidiff.cc
+++ b/tools/abidiff.cc
@@ -1197,15 +1197,15 @@ main(int argc, char* argv[])
 	case abigail::tools_utils::FILE_TYPE_ELF: // fall through
 	case abigail::tools_utils::FILE_TYPE_AR:
 	  {
+	    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
+#ifdef WITH_CTF
+	    if (opts.use_ctf)
+	      requested_fe_kind = corpus::CTF_ORIGIN;
+#endif
 	    abigail::elf_based_reader_sptr rdr =
 	      create_best_elf_based_reader(opts.file1,
 					   opts.prepared_di_root_paths1,
-					   env,
-#ifdef WITH_CTF
-					   opts.use_ctf,
-#else
-                                           false,
-#endif
+					   env, requested_fe_kind,
 					   opts.show_all_types);
             ABG_ASSERT(rdr);
 
@@ -1271,15 +1271,15 @@ main(int argc, char* argv[])
 	case abigail::tools_utils::FILE_TYPE_ELF: // Fall through
 	case abigail::tools_utils::FILE_TYPE_AR:
 	  {
+	    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
+#ifdef WITH_CTF
+	    if (opts.use_ctf)
+	      requested_fe_kind = corpus::CTF_ORIGIN;
+#endif
             abigail::elf_based_reader_sptr rdr =
 	      create_best_elf_based_reader(opts.file2,
 					   opts.prepared_di_root_paths2,
-					   env,
-#ifdef WITH_CTF
-					   opts.use_ctf,
-#else
-					   false,
-#endif
+					   env, requested_fe_kind,
 					   opts.show_all_types);
             ABG_ASSERT(rdr);
 
diff --git a/tools/abidw.cc b/tools/abidw.cc
index d711751f..3b1a1bd5 100644
--- a/tools/abidw.cc
+++ b/tools/abidw.cc
@@ -553,17 +553,18 @@ load_corpus_and_write_abixml(char* argv[],
 
   corpus_sptr corp;
   fe_iface::status s = fe_iface::STATUS_UNKNOWN;
+  corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
+#ifdef WITH_CTF
+  if (opts.use_ctf)
+    requested_fe_kind = corpus::CTF_ORIGIN;
+#endif
+
   // First of all, create a reader to read the ABI from the file
   // specfied in opts ...
   abigail::elf_based_reader_sptr reader =
     create_best_elf_based_reader(opts.in_file_path,
 				 opts.prepared_di_root_paths,
-				 env,
-#ifdef WITH_CTF
-				 opts.use_ctf,
-#else
-				 false,
-#endif
+				 env, requested_fe_kind,
 				 opts.load_all_types,
 				 opts.linux_kernel_mode);
   ABG_ASSERT(reader);
@@ -819,7 +820,7 @@ load_kernel_corpus_group_and_write_abixml(char* argv[],
 
   global_timer.start();
   t.start();
-  corpus::origin origin =
+  corpus::origin requested_fe_kind =
 #ifdef WITH_CTF
     opts.use_ctf ? corpus::CTF_ORIGIN :
 #endif
@@ -830,7 +831,8 @@ load_kernel_corpus_group_and_write_abixml(char* argv[],
 					      opts.vmlinux,
 					      opts.suppression_paths,
 					      opts.kabi_whitelist_paths,
-					      supprs, opts.do_log, env, origin);
+					      supprs, opts.do_log, env,
+					      requested_fe_kind);
   t.stop();
 
   if (opts.do_log)
diff --git a/tools/abipkgdiff.cc b/tools/abipkgdiff.cc
index ecdfb45f..1feb3d9e 100644
--- a/tools/abipkgdiff.cc
+++ b/tools/abipkgdiff.cc
@@ -1323,15 +1323,15 @@ compare(const elf_file&		elf1,
   abigail::elf_based_reader_sptr reader;
   corpus_sptr corpus1;
   {
+    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
+#ifdef WITH_CTF
+    if (opts.use_ctf)
+      requested_fe_kind = corpus::CTF_ORIGIN;
+#endif
     abigail::elf_based_reader_sptr reader =
       create_best_elf_based_reader(elf1.path,
 				   di_dirs1,
-				   env,
-#ifdef WITH_CTF
-				   opts.use_ctf,
-#else
-				   false,
-#endif
+				   env, requested_fe_kind,
 				   opts.show_all_types);
     ABG_ASSERT(reader);
 
@@ -1423,15 +1423,15 @@ compare(const elf_file&		elf1,
 
   corpus_sptr corpus2;
   {
+    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
+#ifdef WITH_CTF
+    if (opts.use_ctf)
+      requested_fe_kind = corpus::CTF_ORIGIN;
+#endif
     abigail::elf_based_reader_sptr reader =
       create_best_elf_based_reader(elf2.path,
 				   di_dirs2,
-				   env,
-#ifdef WITH_CTF
-				   opts.use_ctf,
-#else
-				   false,
-#endif
+				   env, requested_fe_kind,
 				   opts.show_all_types);
     ABG_ASSERT(reader);
 
@@ -1589,15 +1589,15 @@ compare_to_self(const elf_file&		elf,
   corpus_sptr corp;
   abigail::elf_based_reader_sptr reader;
   {
+    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
+#ifdef WITH_CTF
+    if (opts.use_ctf)
+      requested_fe_kind = corpus::CTF_ORIGIN;
+#endif
     abigail::elf_based_reader_sptr reader =
       create_best_elf_based_reader(elf.path,
 				   di_dirs,
-				   env,
-#ifdef WITH_CTF
-				   opts.use_ctf,
-#else
-				   false,
-#endif
+				   env, requested_fe_kind,
 				   opts.show_all_types);
     ABG_ASSERT(reader);
 
diff --git a/tools/kmidiff.cc b/tools/kmidiff.cc
index 391677ca..728392e3 100644
--- a/tools/kmidiff.cc
+++ b/tools/kmidiff.cc
@@ -421,7 +421,7 @@ main(int argc, char* argv[])
 
   corpus_group_sptr group1, group2;
   string debug_info_root_dir;
-  corpus::origin origin =
+  corpus::origin requested_fe_kind =
 #ifdef WITH_CTF
    opts.use_ctf ? corpus::CTF_ORIGIN :
 #endif
@@ -443,8 +443,8 @@ main(int argc, char* argv[])
 						      opts.suppression_paths,
 						      opts.kabi_whitelist_paths,
 						      opts.read_time_supprs,
-						      opts.verbose,
-						      env, origin);
+						      opts.verbose, env,
+						      requested_fe_kind);
 	  print_kernel_dist_binary_paths_under(opts.kernel_dist_root1, opts);
 	}
       else if (ftype == FILE_TYPE_XML_CORPUS_GROUP)
@@ -469,8 +469,8 @@ main(int argc, char* argv[])
 						      opts.suppression_paths,
 						      opts.kabi_whitelist_paths,
 						      opts.read_time_supprs,
-						      opts.verbose,
-						      env, origin);
+						      opts.verbose, env,
+						      requested_fe_kind);
 	  print_kernel_dist_binary_paths_under(opts.kernel_dist_root2, opts);
 	}
       else if (ftype == FILE_TYPE_XML_CORPUS_GROUP)

--------------------------->8<------------------------------------------


So, in the end, please find below the whole final patch that I have applied to the
master branch.

Many thanks!

Cheers,

From 060b2efff7b79ef6010001289974be8fe313024d Mon Sep 17 00:00:00 2001
From: "Guillermo E. Martinez" <guillermo.e.martinez@oracle.com>
Date: Tue, 22 Nov 2022 10:00:50 -0600
Subject: [PATCH] Use the CTF reader by default when applicable

At the moment, the tools abidw, abidiff, abipkgdiff and kmidiff all
use the DWARF front-end by default.  When the "--ctf" option is added
to the command line, they use the CTF front-end.

This patch changes that behaviour in the way described below.

If the "--ctf" command line option is passed to the tool and if the
binary to analyze contains CTF debug info, then the CTF front-end is
used.

If the binary contains ONLY CTF debug info, then the CTF front-end is
used, even if no "--ctf" option was provided.

In all the other cases, the DWARF front-end is used.

Of course, the CTF front-end is not used at all if the CTF
functionality hasn't been enabled at configure time.

This new behaviour is effective for user space and Linux kernel
binaries.

	* doc/manuals/abidiff.rst: Adjust.
	* 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 of the corpus::origin.
	(build_corpus_group_from_kernel_dist_under): Use
	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 the
	`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>
Signed-off-by: Dodji Seketeli <dodji@redhat.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                     |   7 +-
 src/abg-ctf-reader.cc                         | 266 +++++++--------
 src/abg-elf-reader.cc                         |  35 +-
 src/abg-tools-utils.cc                        | 302 ++++++++----------
 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                                |  32 +-
 tools/abipkgdiff.cc                           |  37 ++-
 tools/kmidiff.cc                              |  10 +-
 27 files changed, 626 insertions(+), 448 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..3d7f0d23 100644
--- a/include/abg-tools-utils.h
+++ b/include/abg-tools-utils.h
@@ -317,12 +317,15 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 					  suppr::suppressions_type&	supprs,
 					  bool				verbose,
 					  environment&			env,
-					  corpus::origin	origin = corpus::DWARF_ORIGIN);
+					  corpus::origin	requested_fe_kind = corpus::DWARF_ORIGIN);
 
 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,
+			     corpus::origin requested_debug_info_kind,
+			     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..9bcb9424 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,23 @@ 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;
+	// Not finding any debug info so far is expected if we are
+	// 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 & 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 +404,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 +457,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 +478,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 +508,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 +516,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 +536,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 +559,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 +616,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 +628,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 +655,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 +687,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 +709,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 +716,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 +732,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 +769,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 +776,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 +859,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 +866,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 +880,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 +895,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 +920,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 +946,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 +977,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 +1003,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 +1061,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 +1068,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 +1106,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 +1114,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 +1121,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 +1157,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 +1165,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 +1193,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 +1253,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 +1303,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 +1310,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 +1346,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 +1353,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 +1391,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..3b1b5803 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,21 @@ const Dwarf*
 reader::dwarf_debug_info() const
 {return priv_->dwarf_handle;}
 
+/// Test if the binary has DWARF debug info.
+///
+/// @return true iff the binary has DWARF debug info.
+bool
+reader::has_dwarf_debug_info() const
+{return ((priv_->dwarf_handle != nullptr)
+	  || (priv_->alt_dwarf_handle != nullptr));}
+
+/// Test if the binary has CTF debug info.
+///
+/// @return true iff the binary has CTF debug info.
+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 +892,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..7894219b 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.
@@ -2767,11 +2714,6 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
 /// The main corpus of the @ref corpus_group is made of the vmlinux
 /// binary.  The other corpora are made of the linux kernel binaries.
 ///
-/// Depending of the @ref origin it delegates the corpus build @p group
-/// to:
-///     @ref maybe_load_vmlinux_dwarf_corpus
-///     @ref maybe_load_vmlinux_ctf_corpus
-///
 /// @param root the path of the directory under which the kernel
 /// kernel modules are to be found.  The vmlinux can also be found
 /// somewhere under that directory, but if it's not in there, its path
@@ -2799,6 +2741,9 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
 /// messages.
 ///
 /// @param env the environment to create the corpus_group in.
+///
+/// @param requested_fe_kind the kind of front-end requested by the
+/// user.
 corpus_group_sptr
 build_corpus_group_from_kernel_dist_under(const string&	root,
 					  const string		debug_info_root,
@@ -2808,7 +2753,7 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 					  suppressions_type&	supprs,
 					  bool			verbose,
 					  environment&		env,
-					  corpus::origin	origin)
+					  corpus::origin	requested_fe_kind)
 {
   string vmlinux = vmlinux_path;
   corpus_group_sptr group;
@@ -2836,30 +2781,39 @@ 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);
-#ifdef WITH_CTF
-      maybe_load_vmlinux_ctf_corpus(origin, group, vmlinux,
-                                    modules, root, di_roots,
-                                    verbose, t, env);
-#endif
+      abigail::elf_based_reader_sptr reader =
+        create_best_elf_based_reader(vmlinux,
+                                     di_roots,
+                                     env,
+				     requested_fe_kind,
+                                     /*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;
 }
 
-/// Create the best elf based reader (or front-end), given an ELF file.
+/// Create the best elf based reader (or front-end), given an ELF
+/// file.
+///
+/// This function looks into the ELF file; depending on the kind of
+/// debug info it contains and on the request of the user, the "best"
+/// front-end is created.
 ///
-/// 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.
+/// If the user requested the use of the CTF front-end, then, if the
+/// file contains CTF debug info, the CTF front-end is created,
+/// assuming libabigail is built with CTF support.
 ///
-/// 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.
+/// If the binary ONLY has CTF debug info, then CTF front-end is
+/// created, even if the user hasn't explicitly requested the creation
+/// of the CTF front-end.
+///
+/// Otherwise, by default, the DWARF front-end is created.
 ///
 /// @param elf_file_path a path to the ELF file to consider
 ///
@@ -2868,31 +2822,59 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 ///
 /// @param env the environment to use for the front-end.
 ///
+/// @param requested_fe_kind the kind of front-end specifically
+/// requested by the user. At the moment, only the CTF front-end can
+/// be requested, using the "--ctf" command line option on some tools
+/// using the library.
+///
+/// @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,
+			     corpus::origin requested_fe_kind,
+			     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);
+  if (requested_fe_kind & corpus::CTF_ORIGIN)
+    {
 #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 (file_has_ctf_debug_info(elf_file_path, debug_info_root_paths))
+	result = ctf::create_reader(elf_file_path, debug_info_root_paths, env);
 #endif
+    }
   else
-    result = dwarf::create_reader(elf_file_path,
-				  debug_info_root_paths,
-				  env);
+    {
+      // The user hasn't formally requested the use of the CTF front-end.
+#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))
+	// The file has CTF debug info and no DWARF, let's use the CTF
+	// front end even if it wasn't formally requested by the user.
+	result = ctf::create_reader(elf_file_path, debug_info_root_paths, env);
+#endif
+    }
+
+  if (!result)
+    {
+      // This is the default case.  At worst, the DWARF reader knows
+      // how to handle just ELF data for the case where there is no
+      // DWARF debug info present.
+      result = dwarf::create_reader(elf_file_path,
+				    debug_info_root_paths,
+				    env,
+				    show_all_types,
+				    linux_kernel_mode);
+    }
 
   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..5ffe47a3 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;
+	    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
 #ifdef WITH_CTF
-            if (opts.use_ctf)
-	      rdr = ctf::create_reader(opts.file1,
-				       opts.prepared_di_root_paths1,
-				       env);
-            else
+	    if (opts.use_ctf)
+	      requested_fe_kind = corpus::CTF_ORIGIN;
 #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);
+	    abigail::elf_based_reader_sptr rdr =
+	      create_best_elf_based_reader(opts.file1,
+					   opts.prepared_di_root_paths1,
+					   env, requested_fe_kind,
+					   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;
+	    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
 #ifdef WITH_CTF
-            if (opts.use_ctf)
-	      rdr = ctf::create_reader(opts.file2,
-				       opts.prepared_di_root_paths2,
-				       env);
-            else
+	    if (opts.use_ctf)
+	      requested_fe_kind = corpus::CTF_ORIGIN;
 #endif
-	      rdr = dwarf::create_reader (opts.file2,
-					  opts.prepared_di_root_paths2,
-					  env,
-					  /*read_all_types=*/opts.show_all_types,
-					  opts.linux_kernel_mode);
+            abigail::elf_based_reader_sptr rdr =
+	      create_best_elf_based_reader(opts.file2,
+					   opts.prepared_di_root_paths2,
+					   env, requested_fe_kind,
+					   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..3b1a1bd5 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;
@@ -552,21 +553,21 @@ load_corpus_and_write_abixml(char* argv[],
 
   corpus_sptr corp;
   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;
+  corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
 #ifdef WITH_CTF
   if (opts.use_ctf)
-    reader = abigail::ctf::create_reader(opts.in_file_path,
-					 opts.prepared_di_root_paths,
-					 env);
-  else
+    requested_fe_kind = corpus::CTF_ORIGIN;
 #endif
-    reader = abigail::dwarf::create_reader(opts.in_file_path,
-					   opts.prepared_di_root_paths,
-					   env,
-					   opts.load_all_types,
-					   opts.linux_kernel_mode);
+
+  // First of all, create a reader to read the ABI from the file
+  // specfied in opts ...
+  abigail::elf_based_reader_sptr reader =
+    create_best_elf_based_reader(opts.in_file_path,
+				 opts.prepared_di_root_paths,
+				 env, requested_fe_kind,
+				 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 +820,7 @@ load_kernel_corpus_group_and_write_abixml(char* argv[],
 
   global_timer.start();
   t.start();
-corpus::origin origin =
+  corpus::origin requested_fe_kind =
 #ifdef WITH_CTF
     opts.use_ctf ? corpus::CTF_ORIGIN :
 #endif
@@ -830,7 +831,8 @@ corpus::origin origin =
 					      opts.vmlinux,
 					      opts.suppression_paths,
 					      opts.kabi_whitelist_paths,
-					      supprs, opts.do_log, env, origin);
+					      supprs, opts.do_log, env,
+					      requested_fe_kind);
   t.stop();
 
   if (opts.do_log)
diff --git a/tools/abipkgdiff.cc b/tools/abipkgdiff.cc
index adfe8b8e..1feb3d9e 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;
   {
+    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
 #ifdef WITH_CTF
     if (opts.use_ctf)
-      reader = ctf::create_reader(elf1.path, di_dirs1, env);
-    else
+      requested_fe_kind = corpus::CTF_ORIGIN;
 #endif
-      reader = dwarf::create_reader(elf1.path, di_dirs1, env,
-				    /*load_all_types=*/opts.show_all_types);
-
+    abigail::elf_based_reader_sptr reader =
+      create_best_elf_based_reader(elf1.path,
+				   di_dirs1,
+				   env, requested_fe_kind,
+				   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;
   {
+    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
 #ifdef WITH_CTF
     if (opts.use_ctf)
-      reader = ctf::create_reader(elf2.path, di_dirs2, env);
-    else
+      requested_fe_kind = corpus::CTF_ORIGIN;
 #endif
-      reader = dwarf::create_reader(elf2.path, di_dirs2, env,
-				    /*load_all_types=*/opts.show_all_types);
+    abigail::elf_based_reader_sptr reader =
+      create_best_elf_based_reader(elf2.path,
+				   di_dirs2,
+				   env, requested_fe_kind,
+				   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;
   {
+    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
 #ifdef WITH_CTF
     if (opts.use_ctf)
-      reader = ctf::create_reader(elf.path, di_dirs, env);
-    else
+      requested_fe_kind = corpus::CTF_ORIGIN;
 #endif
-      reader = dwarf::create_reader(elf.path, di_dirs, env,
-				    /*read_all_types=*/opts.show_all_types);
+    abigail::elf_based_reader_sptr reader =
+      create_best_elf_based_reader(elf.path,
+				   di_dirs,
+				   env, requested_fe_kind,
+				   opts.show_all_types);
+    ABG_ASSERT(reader);
 
     corp = reader->read_corpus(c_status);
 
diff --git a/tools/kmidiff.cc b/tools/kmidiff.cc
index 391677ca..728392e3 100644
--- a/tools/kmidiff.cc
+++ b/tools/kmidiff.cc
@@ -421,7 +421,7 @@ main(int argc, char* argv[])
 
   corpus_group_sptr group1, group2;
   string debug_info_root_dir;
-  corpus::origin origin =
+  corpus::origin requested_fe_kind =
 #ifdef WITH_CTF
    opts.use_ctf ? corpus::CTF_ORIGIN :
 #endif
@@ -443,8 +443,8 @@ main(int argc, char* argv[])
 						      opts.suppression_paths,
 						      opts.kabi_whitelist_paths,
 						      opts.read_time_supprs,
-						      opts.verbose,
-						      env, origin);
+						      opts.verbose, env,
+						      requested_fe_kind);
 	  print_kernel_dist_binary_paths_under(opts.kernel_dist_root1, opts);
 	}
       else if (ftype == FILE_TYPE_XML_CORPUS_GROUP)
@@ -469,8 +469,8 @@ main(int argc, char* argv[])
 						      opts.suppression_paths,
 						      opts.kabi_whitelist_paths,
 						      opts.read_time_supprs,
-						      opts.verbose,
-						      env, origin);
+						      opts.verbose, env,
+						      requested_fe_kind);
 	  print_kernel_dist_binary_paths_under(opts.kernel_dist_root2, opts);
 	}
       else if (ftype == FILE_TYPE_XML_CORPUS_GROUP)
-- 
2.38.1



-- 
		Dodji

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

* Re: [PATCH v4] ELF based front-end readers fallback feature
  2022-11-28 15:56       ` Dodji Seketeli
@ 2022-11-28 21:59         ` Guillermo E. Martinez
  0 siblings, 0 replies; 17+ messages in thread
From: Guillermo E. Martinez @ 2022-11-28 21:59 UTC (permalink / raw)
  To: Dodji Seketeli, Guillermo E. Martinez via Libabigail



On 28/11/22 9:56, Dodji Seketeli wrote:
> Hello Guillermo,
> 

Hello Dodji,

> Many thanks for the update!  The patch looks good to me.
> 

Your welcome!.

> I have amended it somewhat and applied the result to the master branch.
> 
> Please find below my comments.
> 
> "Guillermo E. Martinez via Libabigail" <libabigail@sourceware.org> a
> écrit:
> 
>> 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.
> 
> I have slightly amended this part of the commit log.  You'll see the
> resulting patch at the very end of this message.
> 

OK.

> [...]
> 
>> 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
> 
> [...]
> 
> 
>>     /// 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.
> 
> I have slightly amended the comment here to make it read like this:
> 
> +	// Not finding any debug info so far is expected if we are
> +	// 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))
> 
> the STATUS_DEBUG_INFO_NOT_FOUND bit cannot be set here because you have
> unset it above by doing:
> 
>> +        status &= static_cast<abigail::fe_iface::status>
>> +                    (~STATUS_DEBUG_INFO_NOT_FOUND);
> 
> So I have changed that condition to make it read:
> 

OK.

> +    if ((status & STATUS_NO_SYMBOLS_FOUND)
> +	|| !(status & STATUS_OK))
> 
> [...]
> 
> 
>> 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
> 
> [...]
> 
> 
>>   
>> +bool
>> +reader::has_dwarf_debug_info() const
> 
> I have added a doxygen comment to this function.
> 
>> +{return ((priv_->dwarf_handle != nullptr)
>> +	  || (priv_->alt_dwarf_handle != nullptr));}
>> +
>> +bool
>> +reader::has_ctf_debug_info() const
> 
> Likewise.
> 
>> +{return (priv_->ctf_section != nullptr);}
>> +
> 
> [...]
> 
>> diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
>> index 8898ef97..0a523b87 100644
> 
> [...]
> 
>> 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,
> 
> Rather than adding a boolean here, I have added a parameter
> 'corpus::origin requested_fe_kind'.  This is basically the kind of
> front-end requested by the user when invoking the tool.  For instance,
> if --ctf is provided on the command line, requested_fe_kind should be
> set to corpus::CTF_ORIGIN.  If nothing is provided on the command line,
> either requested_fe_kind could be set to either
> corpus::ARTIFICIAL_ORIGIN or corpus::DWARF_ORIGIN.  When we have another
> kind of front-end tomorrow, requested_fe_kind will still be able to be
> used because that new front-end is likely to be for a new kind
> corpus::origin.  So, I think that doing this is a more generic solution.
> 

Oh, much better to be ready for adding new frond-ends.

>> +			     bool show_all_types,
>> +			     bool linux_kernel_mode = false);
>>   
>>   }// end namespace tools_utils
>>   
> 
>> --- a/src/abg-tools-utils.cc
>> +++ b/src/abg-tools-utils.cc
>> @@ -405,6 +405,23 @@ is_regular_file(const string& path)
>>     return false;
>>   }
> 
> [...]
> 
>> @@ -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)
> 
> Following my comment above about the declaration of this function, I
> have updated its definition here.
> 
> Near the end of this message, I'll paste my changes against the tree
> containing your patch, so that you can see clearly the changes I've made
> to create_best_elf_based_reader and to all the other related parts of
> the patch.  But right now, please find the hunk I have come up with
> about this specific location of the source code:

OK.

> 
>      -/// Create the best elf based reader (or front-end), given an ELF file.
>      +/// Create the best elf based reader (or front-end), given an ELF
>      +/// file.
>      +///
>      +/// This function looks into the ELF file; depending on the kind of
>      +/// debug info it contains and on the request of the user, the "best"
>      +/// front-end is created.
>       ///
>      -/// This function looks into the ELF file.  If it contains DWARF debug
>      -/// 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.
>      +/// If the user requested the use of the CTF front-end, then, if the
>      +/// file contains CTF debug info, the CTF front-end is created,
>      +/// assuming libabigail is built with CTF support.
>       ///
>      -/// By other hand, it selects the DWARF front-end when @ref use_ctf is
>      -/// true but ELF file doesn't have CTF debug information.
>      +/// If the binary ONLY has CTF debug info, then CTF front-end is
>      +/// created, even if the user hasn't explicitly requested the creation
>      +/// of the CTF front-end.
>       ///
>      -/// Otherwise, if the file contains no debug info or if the king of
>      -/// debug info is not yet recognized, a DWARF or CTF  Reader front-end is
>      -/// created and returned depending of @ref use_ctf parameter.
>      +/// Otherwise, by default, the DWARF front-end is created.
>       ///
>       /// @param elf_file_path a path to the ELF file to consider
>       ///
>      @@ -2825,7 +2824,10 @@ 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 requested_fe_kind the kind of front-end specifically
>      +/// requested by the user. At the moment, only the CTF front-end can
>      +/// be requested, using the "--ctf" command line option on some tools
>      +/// using the library.
>       ///
>       /// @param show_all_types option to be passed to elf based readers.
>       ///
>      @@ -2837,7 +2839,7 @@ elf_based_reader_sptr
>       create_best_elf_based_reader(const string& elf_file_path,
>                                   const vector<char**>& debug_info_root_paths,
>                                   environment& env,
>      -			     bool use_ctf,
>      +			     corpus::origin requested_fe_kind,
>                                   bool show_all_types,
>                                   bool linux_kernel_mode)
>       {
>      @@ -2845,41 +2847,36 @@ create_best_elf_based_reader(const string& elf_file_path,
>         if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
>           return result;
> 
>      +  if (requested_fe_kind & corpus::CTF_ORIGIN)
>      +    {
>       #ifdef WITH_CTF
>      -  if (!use_ctf)
>      +      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);
>      +#endif
>      +    }
>      +  else
>           {
>      +      // The user hasn't formally requested the use of the CTF front-end.
>      +#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))
>      +	// The file has CTF debug info and no DWARF, let's use the CTF
>      +	// front end even if it wasn't formally requested by the user.
>      +	result = ctf::create_reader(elf_file_path, debug_info_root_paths, env);
>       #endif
>      +    }
>      +
>      +  if (!result)
>      +    {
>      +      // This is the default case.  At worst, the DWARF reader knows
>      +      // how to handle just ELF data for the case where there is no
>      +      // DWARF debug info present.
>             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 = 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;
>       }
> 
> [...]
> 
> I have adjusted the rest of the code accordingly.
> 
> Please find below the diff of my changed related to
> create_best_elf_based_reader and to other related parts.
> 
> --------------------------->8<------------------------------------------
> diff --git a/include/abg-tools-utils.h b/include/abg-tools-utils.h
> index 13d6ad75..3d7f0d23 100644
> --- a/include/abg-tools-utils.h
> +++ b/include/abg-tools-utils.h
> @@ -317,13 +317,13 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
>   					  suppr::suppressions_type&	supprs,
>   					  bool				verbose,
>   					  environment&			env,
> -					  corpus::origin	origin = corpus::DWARF_ORIGIN);
> +					  corpus::origin	requested_fe_kind = corpus::DWARF_ORIGIN);
>   
>   elf_based_reader_sptr
>   create_best_elf_based_reader(const string& elf_file_path,
>   			     const vector<char**>& debug_info_root_paths,
>   			     environment& env,
> -			     bool use_ctf,
> +			     corpus::origin requested_debug_info_kind,
>   			     bool show_all_types,
>   			     bool linux_kernel_mode = false);
>   
> diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
> index 0a523b87..b089b69c 100644
> --- a/src/abg-tools-utils.cc
> +++ b/src/abg-tools-utils.cc
> @@ -2755,7 +2755,7 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
>   					  suppressions_type&	supprs,
>   					  bool			verbose,
>   					  environment&		env,
> -					  corpus::origin	origin)
> +					  corpus::origin	requested_fe_kind)
>   {
>     string vmlinux = vmlinux_path;
>     corpus_group_sptr group;
> @@ -2787,11 +2787,7 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
>           create_best_elf_based_reader(vmlinux,
>                                        di_roots,
>                                        env,
> -#ifdef WITH_CTF
> -                                     origin & corpus::CTF_ORIGIN,
> -#else
> -                                     false,
> -#endif
> +				     requested_fe_kind,
>                                        /*read_all_types=*/false,
>                                        /*linux_kernel_mode=*/true);
>         ABG_ASSERT(reader);
> @@ -2804,19 +2800,22 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
>     return group;
>   }
>   
> -/// Create the best elf based reader (or front-end), given an ELF file.
> +/// Create the best elf based reader (or front-end), given an ELF
> +/// file.
> +///
> +/// This function looks into the ELF file; depending on the kind of
> +/// debug info it contains and on the request of the user, the "best"
> +/// front-end is created.
>   ///
> -/// This function looks into the ELF file.  If it contains DWARF debug
> -/// 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.
> +/// If the user requested the use of the CTF front-end, then, if the
> +/// file contains CTF debug info, the CTF front-end is created,
> +/// assuming libabigail is built with CTF support.
>   ///
> -/// By other hand, it selects the DWARF front-end when @ref use_ctf is
> -/// true but ELF file doesn't have CTF debug information.
> +/// If the binary ONLY has CTF debug info, then CTF front-end is
> +/// created, even if the user hasn't explicitly requested the creation
> +/// of the CTF front-end.
>   ///
> -/// Otherwise, if the file contains no debug info or if the king of
> -/// debug info is not yet recognized, a DWARF or CTF  Reader front-end is
> -/// created and returned depending of @ref use_ctf parameter.
> +/// Otherwise, by default, the DWARF front-end is created.
>   ///
>   /// @param elf_file_path a path to the ELF file to consider
>   ///
> @@ -2825,7 +2824,10 @@ 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 requested_fe_kind the kind of front-end specifically
> +/// requested by the user. At the moment, only the CTF front-end can
> +/// be requested, using the "--ctf" command line option on some tools
> +/// using the library.
>   ///
>   /// @param show_all_types option to be passed to elf based readers.
>   ///
> @@ -2837,7 +2839,7 @@ elf_based_reader_sptr
>   create_best_elf_based_reader(const string& elf_file_path,
>   			     const vector<char**>& debug_info_root_paths,
>   			     environment& env,
> -			     bool use_ctf,
> +			     corpus::origin requested_fe_kind,
>   			     bool show_all_types,
>   			     bool linux_kernel_mode)
>   {
> @@ -2845,41 +2847,36 @@ create_best_elf_based_reader(const string& elf_file_path,
>     if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
>       return result;
>   
> +  if (requested_fe_kind & corpus::CTF_ORIGIN)
> +    {
>   #ifdef WITH_CTF
> -  if (!use_ctf)
> +      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);
> +#endif
> +    }
> +  else
>       {
> +      // The user hasn't formally requested the use of the CTF front-end.
> +#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))
> +	// The file has CTF debug info and no DWARF, let's use the CTF
> +	// front end even if it wasn't formally requested by the user.
> +	result = ctf::create_reader(elf_file_path, debug_info_root_paths, env);
>   #endif
> +    }
> +
> +  if (!result)
> +    {
> +      // This is the default case.  At worst, the DWARF reader knows
> +      // how to handle just ELF data for the case where there is no
> +      // DWARF debug info present.
>         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 = 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/tools/abidiff.cc b/tools/abidiff.cc
> index 6cd948bf..5ffe47a3 100644
> --- a/tools/abidiff.cc
> +++ b/tools/abidiff.cc
> @@ -1197,15 +1197,15 @@ main(int argc, char* argv[])
>   	case abigail::tools_utils::FILE_TYPE_ELF: // fall through
>   	case abigail::tools_utils::FILE_TYPE_AR:
>   	  {
> +	    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
> +#ifdef WITH_CTF
> +	    if (opts.use_ctf)
> +	      requested_fe_kind = corpus::CTF_ORIGIN;
> +#endif
>   	    abigail::elf_based_reader_sptr rdr =
>   	      create_best_elf_based_reader(opts.file1,
>   					   opts.prepared_di_root_paths1,
> -					   env,
> -#ifdef WITH_CTF
> -					   opts.use_ctf,
> -#else
> -                                           false,
> -#endif
> +					   env, requested_fe_kind,
>   					   opts.show_all_types);
>               ABG_ASSERT(rdr);
>   
> @@ -1271,15 +1271,15 @@ main(int argc, char* argv[])
>   	case abigail::tools_utils::FILE_TYPE_ELF: // Fall through
>   	case abigail::tools_utils::FILE_TYPE_AR:
>   	  {
> +	    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
> +#ifdef WITH_CTF
> +	    if (opts.use_ctf)
> +	      requested_fe_kind = corpus::CTF_ORIGIN;
> +#endif
>               abigail::elf_based_reader_sptr rdr =
>   	      create_best_elf_based_reader(opts.file2,
>   					   opts.prepared_di_root_paths2,
> -					   env,
> -#ifdef WITH_CTF
> -					   opts.use_ctf,
> -#else
> -					   false,
> -#endif
> +					   env, requested_fe_kind,
>   					   opts.show_all_types);
>               ABG_ASSERT(rdr);
>   
> diff --git a/tools/abidw.cc b/tools/abidw.cc
> index d711751f..3b1a1bd5 100644
> --- a/tools/abidw.cc
> +++ b/tools/abidw.cc
> @@ -553,17 +553,18 @@ load_corpus_and_write_abixml(char* argv[],
>   
>     corpus_sptr corp;
>     fe_iface::status s = fe_iface::STATUS_UNKNOWN;
> +  corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
> +#ifdef WITH_CTF
> +  if (opts.use_ctf)
> +    requested_fe_kind = corpus::CTF_ORIGIN;
> +#endif
> +
>     // First of all, create a reader to read the ABI from the file
>     // specfied in opts ...
>     abigail::elf_based_reader_sptr reader =
>       create_best_elf_based_reader(opts.in_file_path,
>   				 opts.prepared_di_root_paths,
> -				 env,
> -#ifdef WITH_CTF
> -				 opts.use_ctf,
> -#else
> -				 false,
> -#endif
> +				 env, requested_fe_kind,
>   				 opts.load_all_types,
>   				 opts.linux_kernel_mode);
>     ABG_ASSERT(reader);
> @@ -819,7 +820,7 @@ load_kernel_corpus_group_and_write_abixml(char* argv[],
>   
>     global_timer.start();
>     t.start();
> -  corpus::origin origin =
> +  corpus::origin requested_fe_kind =
>   #ifdef WITH_CTF
>       opts.use_ctf ? corpus::CTF_ORIGIN :
>   #endif
> @@ -830,7 +831,8 @@ load_kernel_corpus_group_and_write_abixml(char* argv[],
>   					      opts.vmlinux,
>   					      opts.suppression_paths,
>   					      opts.kabi_whitelist_paths,
> -					      supprs, opts.do_log, env, origin);
> +					      supprs, opts.do_log, env,
> +					      requested_fe_kind);
>     t.stop();
>   
>     if (opts.do_log)
> diff --git a/tools/abipkgdiff.cc b/tools/abipkgdiff.cc
> index ecdfb45f..1feb3d9e 100644
> --- a/tools/abipkgdiff.cc
> +++ b/tools/abipkgdiff.cc
> @@ -1323,15 +1323,15 @@ compare(const elf_file&		elf1,
>     abigail::elf_based_reader_sptr reader;
>     corpus_sptr corpus1;
>     {
> +    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
> +#ifdef WITH_CTF
> +    if (opts.use_ctf)
> +      requested_fe_kind = corpus::CTF_ORIGIN;
> +#endif
>       abigail::elf_based_reader_sptr reader =
>         create_best_elf_based_reader(elf1.path,
>   				   di_dirs1,
> -				   env,
> -#ifdef WITH_CTF
> -				   opts.use_ctf,
> -#else
> -				   false,
> -#endif
> +				   env, requested_fe_kind,
>   				   opts.show_all_types);
>       ABG_ASSERT(reader);
>   
> @@ -1423,15 +1423,15 @@ compare(const elf_file&		elf1,
>   
>     corpus_sptr corpus2;
>     {
> +    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
> +#ifdef WITH_CTF
> +    if (opts.use_ctf)
> +      requested_fe_kind = corpus::CTF_ORIGIN;
> +#endif
>       abigail::elf_based_reader_sptr reader =
>         create_best_elf_based_reader(elf2.path,
>   				   di_dirs2,
> -				   env,
> -#ifdef WITH_CTF
> -				   opts.use_ctf,
> -#else
> -				   false,
> -#endif
> +				   env, requested_fe_kind,
>   				   opts.show_all_types);
>       ABG_ASSERT(reader);
>   
> @@ -1589,15 +1589,15 @@ compare_to_self(const elf_file&		elf,
>     corpus_sptr corp;
>     abigail::elf_based_reader_sptr reader;
>     {
> +    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
> +#ifdef WITH_CTF
> +    if (opts.use_ctf)
> +      requested_fe_kind = corpus::CTF_ORIGIN;
> +#endif
>       abigail::elf_based_reader_sptr reader =
>         create_best_elf_based_reader(elf.path,
>   				   di_dirs,
> -				   env,
> -#ifdef WITH_CTF
> -				   opts.use_ctf,
> -#else
> -				   false,
> -#endif
> +				   env, requested_fe_kind,
>   				   opts.show_all_types);
>       ABG_ASSERT(reader);
>   
> diff --git a/tools/kmidiff.cc b/tools/kmidiff.cc
> index 391677ca..728392e3 100644
> --- a/tools/kmidiff.cc
> +++ b/tools/kmidiff.cc
> @@ -421,7 +421,7 @@ main(int argc, char* argv[])
>   
>     corpus_group_sptr group1, group2;
>     string debug_info_root_dir;
> -  corpus::origin origin =
> +  corpus::origin requested_fe_kind =
>   #ifdef WITH_CTF
>      opts.use_ctf ? corpus::CTF_ORIGIN :
>   #endif
> @@ -443,8 +443,8 @@ main(int argc, char* argv[])
>   						      opts.suppression_paths,
>   						      opts.kabi_whitelist_paths,
>   						      opts.read_time_supprs,
> -						      opts.verbose,
> -						      env, origin);
> +						      opts.verbose, env,
> +						      requested_fe_kind);
>   	  print_kernel_dist_binary_paths_under(opts.kernel_dist_root1, opts);
>   	}
>         else if (ftype == FILE_TYPE_XML_CORPUS_GROUP)
> @@ -469,8 +469,8 @@ main(int argc, char* argv[])
>   						      opts.suppression_paths,
>   						      opts.kabi_whitelist_paths,
>   						      opts.read_time_supprs,
> -						      opts.verbose,
> -						      env, origin);
> +						      opts.verbose, env,
> +						      requested_fe_kind);
>   	  print_kernel_dist_binary_paths_under(opts.kernel_dist_root2, opts);
>   	}
>         else if (ftype == FILE_TYPE_XML_CORPUS_GROUP)
> 
> --------------------------->8<------------------------------------------
> 
> 
> So, in the end, please find below the whole final patch that I have applied to the
> master branch.
> 
> Many thanks!
> 

Thanks to you for comments and review!


> Cheers,
> 
> [...]

Best regards,
guillermo

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

end of thread, other threads:[~2022-11-28 21:59 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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     ` [PATCH v4] " Guillermo E. Martinez
2022-11-28 15:56       ` Dodji Seketeli
2022-11-28 21:59         ` Guillermo E. Martinez

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