[v4] ELF based front-end readers fallback feature

Message ID 20221122160050.2031623-1-guillermo.e.martinez@oracle.com
State New
Headers
Series [v4] ELF based front-end readers fallback feature |

Commit Message

Guillermo E. Martinez Nov. 22, 2022, 4 p.m. UTC
  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

new file mode 100644
index 00000000..ebbae7ef
index e128ff63..8e510ca2 100644
  

Comments

Dodji Seketeli Nov. 28, 2022, 3:56 p.m. UTC | #1
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)
  
Guillermo E. Martinez Nov. 28, 2022, 9:59 p.m. UTC | #2
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
  

Patch

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