[v2] ctf-reader: add support to looking debug information in external path

Message ID 20220516183254.2042821-1-guillermo.e.martinez@oracle.com
State New
Headers
Series [v2] ctf-reader: add support to looking debug information in external path |

Commit Message

Guillermo E. Martinez May 16, 2022, 6:32 p.m. UTC
  Hello libabigail team,

This is the patch v2 to add support for looking debug information in
external path(s) in CTF reader. Changes from v1:

 * Rebase from master branch

Comments will be welcomed!

Kinds regards,
Guillermo

When an ELF `stripped' file is used to get CTF debug information the ELF
symbols used by ctf reader (`symtab_reader::symtab') is split in a
separate file and even though CTF was designed to be in ELF file after
be `stripped' this .ctf section can be 'loaded'  from and external
.debug file, for instance the script `find-debuginfo' used to generate
RPM debug packages split debug information in .debug files. The location
of such files is pass as a standard argument from libabigail tools and
the name of the file is gathering from the `.gnu_debuglink' section.

	* include/abg-ctf-reader.h (ctf_reader::create_read_context):
	Add `debug_info_root_paths' argument.
	(ctf_reader::reset_read_context): Likewise.
	* src/abg-ctf-reader.cc: Add `read_context::elf_{handler,fd}_dbg',
	data members.
	(read_context::read_context): Add new `debug_info_root_paths'
	argument.
	(read_context::initialize): Likewise.
	(ctf_reader::create_read_context): Likewise.
	(ctf_reader::close_elf_handler): Release
	`read_context::elf_{handler,fd}_dbg' members.
	(ctf_reader::find_alt_debuginfo): Add new function.
	(ctf_reader::slurp_elf_info): Add new argument `status'. Use
	`find_alt_debuginfo' and `elf_helpers::find_section_by_name'
	to read the symtab and ctf information from an external .debug
	file, the `status' reference is updated.
	(ctf_reader::read_corpus): Verify `status' after `slurp_elf_info'.
	(ctf_reader::reset_read_context): Add new `debug_info_root_path'
	argument.
	* src/abg-elf-helpers.cc (elf_helpers::find_section_by_name): Update
	comment.
	* src/abg-tools-utils.cc (maybe_load_vmlinux_ctf_corpus):
	Adjust `ctf_reader::{create,reset}_read_context'.
	* tests/test-read-ctf.cc: Likewise.
	* tools/abidiff.cc (display_usage): Add `--ctf' command line
	option.
	(main): Adjust `ctf_reader::create_read_context'.
	Likewise.
	* tools/abidw.cc (load_corpus_and_write_abixml): Adjust
	`ctf_reader::create_read_context'.
	* tools/abilint.cc: Likewise.

Signed-off-by: Guillermo E. Martinez <guillermo.e.martinez@oracle.com>
---
 include/abg-ctf-reader.h |   2 +
 src/abg-ctf-reader.cc    | 176 ++++++++++++++++++++++++++++++---------
 src/abg-elf-helpers.cc   |   2 +
 src/abg-tools-utils.cc   |  11 ++-
 tests/test-read-ctf.cc   |   3 +
 tools/abidiff.cc         |   6 +-
 tools/abidw.cc           |   6 +-
 tools/abilint.cc         |   7 +-
 8 files changed, 165 insertions(+), 48 deletions(-)
  

Comments

Dodji Seketeli May 17, 2022, 2:33 p.m. UTC | #1
Hello,

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


> When an ELF `stripped' file is used to get CTF debug information the ELF
> symbols used by ctf reader (`symtab_reader::symtab') is split in a
> separate file and even though CTF was designed to be in ELF file after
> be `stripped' this .ctf section can be 'loaded'  from and external
> .debug file, for instance the script `find-debuginfo' used to generate
> RPM debug packages split debug information in .debug files. The location
> of such files is pass as a standard argument from libabigail tools and
> the name of the file is gathering from the `.gnu_debuglink' section.
>
> 	* include/abg-ctf-reader.h (ctf_reader::create_read_context):
> 	Add `debug_info_root_paths' argument.
> 	(ctf_reader::reset_read_context): Likewise.
> 	* src/abg-ctf-reader.cc: Add `read_context::elf_{handler,fd}_dbg',
> 	data members.
> 	(read_context::read_context): Add new `debug_info_root_paths'
> 	argument.
> 	(read_context::initialize): Likewise.
> 	(ctf_reader::create_read_context): Likewise.
> 	(ctf_reader::close_elf_handler): Release
> 	`read_context::elf_{handler,fd}_dbg' members.
> 	(ctf_reader::find_alt_debuginfo): Add new function.
> 	(ctf_reader::slurp_elf_info): Add new argument `status'. Use
> 	`find_alt_debuginfo' and `elf_helpers::find_section_by_name'
> 	to read the symtab and ctf information from an external .debug
> 	file, the `status' reference is updated.
> 	(ctf_reader::read_corpus): Verify `status' after `slurp_elf_info'.
> 	(ctf_reader::reset_read_context): Add new `debug_info_root_path'
> 	argument.
> 	* src/abg-elf-helpers.cc (elf_helpers::find_section_by_name): Update
> 	comment.
> 	* src/abg-tools-utils.cc (maybe_load_vmlinux_ctf_corpus):
> 	Adjust `ctf_reader::{create,reset}_read_context'.
> 	* tests/test-read-ctf.cc: Likewise.
> 	* tools/abidiff.cc (display_usage): Add `--ctf' command line
> 	option.
> 	(main): Adjust `ctf_reader::create_read_context'.
> 	Likewise.
> 	* tools/abidw.cc (load_corpus_and_write_abixml): Adjust
> 	`ctf_reader::create_read_context'.
> 	* tools/abilint.cc: Likewise.

I have also adjusted the use of the ctf reader in abipkgdiff.

Please find below the resulting patch that was applied to master.
Thanks!

>
> Signed-off-by: Guillermo E. Martinez <guillermo.e.martinez@oracle.com>

Applied to master.

[...]

From 1ebd5ff0eb09e6fe78d45065d3bb9bb02468d37c Mon Sep 17 00:00:00 2001
From: "Guillermo E. Martinez" <guillermo.e.martinez@oracle.com>
Date: Mon, 16 May 2022 13:32:54 -0500
Subject: [PATCH] ctf-reader: add support to looking debug information in
 external path

When an ELF `stripped' file is used to get CTF debug information the ELF
symbols used by ctf reader (`symtab_reader::symtab') is split in a
separate file and even though CTF was designed to be in ELF file after
be `stripped' this .ctf section can be 'loaded'  from and external
.debug file, for instance the script `find-debuginfo' used to generate
RPM debug packages split debug information in .debug files. The location
of such files is pass as a standard argument from libabigail tools and
the name of the file is gathering from the `.gnu_debuglink' section.

	* include/abg-ctf-reader.h (ctf_reader::create_read_context):
	Add `debug_info_root_paths' argument.
	(ctf_reader::reset_read_context): Likewise.
	* src/abg-ctf-reader.cc: Add `read_context::elf_{handler,fd}_dbg',
	data members.
	(read_context::read_context): Add new `debug_info_root_paths'
	argument.
	(read_context::initialize): Likewise.
	(ctf_reader::create_read_context): Likewise.
	(ctf_reader::close_elf_handler): Release
	`read_context::elf_{handler,fd}_dbg' members.
	(ctf_reader::find_alt_debuginfo): Add new function.
	(ctf_reader::slurp_elf_info): Add new argument `status'. Use
	`find_alt_debuginfo' and `elf_helpers::find_section_by_name'
	to read the symtab and ctf information from an external .debug
	file, the `status' reference is updated.
	(ctf_reader::read_corpus): Verify `status' after `slurp_elf_info'.
	(ctf_reader::reset_read_context): Add new `debug_info_root_path'
	argument.
	* src/abg-elf-helpers.cc (elf_helpers::find_section_by_name): Update
	comment.
	* src/abg-tools-utils.cc (maybe_load_vmlinux_ctf_corpus):
	Adjust `ctf_reader::{create,reset}_read_context'.
	* tests/test-read-ctf.cc: Likewise.
	* tools/abidiff.cc (display_usage): Add `--ctf' command line
	option.
	(main): Adjust `ctf_reader::create_read_context'.
	Likewise.
	* tools/abidw.cc (load_corpus_and_write_abixml): Adjust
	`ctf_reader::create_read_context'.
	* tools/abilint.cc (main): Likewise.
	* tools/abipkgdiff.cc (compare, compare_to_self): Likewise.

Signed-off-by: Guillermo E. Martinez <guillermo.e.martinez@oracle.com>
Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 include/abg-ctf-reader.h |   2 +
 src/abg-ctf-reader.cc    | 176 ++++++++++++++++++++++++++++++---------
 src/abg-elf-helpers.cc   |   2 +
 src/abg-tools-utils.cc   |  11 ++-
 tests/test-read-ctf.cc   |   3 +
 tools/abidiff.cc         |   6 +-
 tools/abidw.cc           |   6 +-
 tools/abilint.cc         |   7 +-
 tools/abipkgdiff.cc      |   3 +
 9 files changed, 168 insertions(+), 48 deletions(-)

diff --git a/include/abg-ctf-reader.h b/include/abg-ctf-reader.h
index ba7289aa..60f3623d 100644
--- a/include/abg-ctf-reader.h
+++ b/include/abg-ctf-reader.h
@@ -31,6 +31,7 @@ typedef shared_ptr<read_context> read_context_sptr;
 
 read_context_sptr
 create_read_context(const std::string& elf_path,
+                    const vector<char**>& debug_info_root_paths,
                     ir::environment *env);
 corpus_sptr
 read_corpus(read_context *ctxt, elf_reader::status& status);
@@ -47,6 +48,7 @@ set_read_context_corpus_group(read_context& ctxt, corpus_group_sptr& group);
 void
 reset_read_context(read_context_sptr &ctxt,
                    const std::string&	elf_path,
+                   const vector<char**>& debug_info_root_path,
                    ir::environment*	environment);
 std::string
 dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type);
diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 89dea276..2bb3d924 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -70,6 +70,10 @@ public:
   Elf *elf_handler;
   int elf_fd;
 
+  /// libelf handler for the ELF file from which we read the CTF data,
+  /// and the corresponding file descriptor found in external .debug file
+  Elf *elf_handler_dbg;
+  int elf_fd_dbg;
 
   /// The symtab read from the ELF file.
   symtab_reader::symtab_sptr symtab;
@@ -83,6 +87,8 @@ public:
   corpus_sptr			cur_corpus_;
   corpus_group_sptr		cur_corpus_group_;
   corpus::exported_decls_builder* exported_decls_builder_;
+  // The set of directories under which to look for debug info.
+  vector<char**>		debug_info_root_paths_;
 
   /// Setter of the exported decls builder object.
   ///
@@ -253,15 +259,20 @@ public:
   ///
   /// @param elf_path the path to the ELF file.
   ///
-  /// @param environment the environment used by the current context.
+  /// @param debug_info_root_paths vector with the paths
+  /// to directories where .debug file is located.
+  ///
+  /// @param env the environment used by the current context.
   /// This environment contains resources needed by the reader and by
   /// the types and declarations that are to be created later.  Note
   /// that ABI artifacts that are to be compared all need to be
   /// created within the same environment.
-  read_context(const string& elf_path, ir::environment *env) :
-    ctfa(NULL)
+  read_context(const string& elf_path,
+               const vector<char**>& debug_info_root_paths,
+               ir::environment *env) :
+   ctfa(NULL)
   {
-    initialize(elf_path, env);
+    initialize(elf_path, debug_info_root_paths, env);
   }
 
   /// Initializer of read_context.
@@ -269,6 +280,9 @@ public:
   /// @param elf_path the path to the elf file the context is to be
   /// used for.
   ///
+  /// @param debug_info_root_paths vector with the paths
+  /// to directories where .debug file is located.
+  ///
   /// @param environment the environment used by the current context.
   /// This environment contains resources needed by the reader and by
   /// the types and declarations that are to be created later.  Note
@@ -279,16 +293,22 @@ public:
   /// must be greater than the life time of the resulting @ref
   /// read_context the context uses resources that are allocated in
   /// the environment.
-  void initialize(const string& elf_path, ir::environment *env)
+  void
+  initialize(const string& elf_path,
+             const vector<char**>& debug_info_root_paths,
+             ir::environment *env)
   {
     types_map.clear();
     filename = elf_path;
     ir_env = env;
     elf_handler = NULL;
+    elf_handler_dbg = NULL;
     elf_fd = -1;
+    elf_fd_dbg = -1;
     symtab.reset();
     cur_corpus_group_.reset();
     exported_decls_builder_ = 0;
+    debug_info_root_paths_ = debug_info_root_paths;
   }
 
   ~read_context()
@@ -1332,6 +1352,10 @@ close_elf_handler (read_context *ctxt)
   /* Finish the ELF handler and close the associated file.  */
   elf_end(ctxt->elf_handler);
   close(ctxt->elf_fd);
+
+  /* Finish the ELF handler and close the associated debug file.  */
+  elf_end(ctxt->elf_handler_dbg);
+  close(ctxt->elf_fd_dbg);
 }
 
 /// Fill a CTF section description with the information in a given ELF
@@ -1358,38 +1382,113 @@ fill_ctf_section(Elf_Scn *elf_section, ctf_sect_t *ctf_section)
   ctf_section->cts_entsize = section_header->sh_entsize;
 }
 
+/// Find a CTF section and debug symbols in a given ELF using
+/// .gnu_debuglink section.
+///
+/// @param ctxt the read context.
+/// @param ctf_dbg_section the CTF section to fill with the raw data.
+static void
+find_alt_debuginfo(read_context *ctxt, Elf_Scn **ctf_dbg_scn)
+{
+  std::string name;
+  Elf_Data *data;
+
+  Elf_Scn *section = elf_helpers::find_section
+    (ctxt->elf_handler, ".gnu_debuglink", SHT_PROGBITS);
+
+  if (section
+      && (data = elf_getdata(section, NULL))
+      && data->d_size != 0)
+    name = (char *) data->d_buf;
+
+  int fd = -1;
+  Elf *hdlr = NULL;
+  *ctf_dbg_scn = NULL;
+
+  if (!name.empty())
+    for (vector<char**>::const_iterator i = ctxt->debug_info_root_paths_.begin();
+         i != ctxt->debug_info_root_paths_.end();
+         ++i)
+      {
+        std::string file_path;
+        if (!tools_utils::find_file_under_dir(**i, name, file_path))
+          continue;
+
+        if ((fd = open(file_path.c_str(), O_RDONLY)) == -1)
+          continue;
+
+        if ((hdlr = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
+          {
+            close(fd);
+            continue;
+          }
+
+        ctxt->symtab =
+          symtab_reader::symtab::load(hdlr, ctxt->ir_env, nullptr);
+
+        // unlikely .ctf was designed to be present in stripped file
+        *ctf_dbg_scn =
+          elf_helpers::find_section(hdlr, ".ctf", SHT_PROGBITS);
+          break;
+
+        elf_end(hdlr);
+        close(fd);
+      }
+
+  // If we don't have a symbol table, use current one in ELF file
+  if (!ctxt->symtab)
+    ctxt->symtab =
+     symtab_reader::symtab::load(ctxt->elf_handler, ctxt->ir_env, nullptr);
+
+  ctxt->elf_handler_dbg = hdlr;
+  ctxt->elf_fd_dbg = fd;
+}
+
 /// Slurp certain information from the ELF file described by a given
 /// read context and install it in a libabigail corpus.
 ///
 /// @param ctxt the read context
 /// @param corp the libabigail corpus in which to install the info.
-///
-/// @return 0 if there is an error.
-/// @return 1 otherwise.
-
-static int
-slurp_elf_info(read_context *ctxt, corpus_sptr corp)
+/// @param status the resulting status flags.
+static void
+slurp_elf_info(read_context *ctxt,
+               corpus_sptr corp,
+               elf_reader::status& status)
 {
+  /* Set the ELF architecture.  */
+  GElf_Ehdr *ehdr, eh_mem;
   Elf_Scn *symtab_scn;
-  Elf_Scn *ctf_scn;
+  Elf_Scn *ctf_scn, *ctf_dbg_scn;
   Elf_Scn *strtab_scn;
-  GElf_Ehdr eh_mem;
-  GElf_Ehdr *ehdr = gelf_getehdr(ctxt->elf_handler, &eh_mem);
 
-  /* Set the ELF architecture.  */
+  if (!(ehdr = gelf_getehdr(ctxt->elf_handler, &eh_mem)))
+      return;
+
   corp->set_architecture_name(elf_helpers::e_machine_to_string(ehdr->e_machine));
 
-  /* Read the symtab from the ELF file and set it in the corpus.  */
-  ctxt->symtab =
-    symtab_reader::symtab::load(ctxt->elf_handler, ctxt->ir_env,
-                                0 /* No suppressions.  */);
+  find_alt_debuginfo(ctxt, &ctf_dbg_scn);
+  ABG_ASSERT(ctxt->symtab);
   corp->set_symtab(ctxt->symtab);
 
   if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
-    return 1;
+    {
+      status |= elf_reader::STATUS_OK;
+      return;
+    }
 
   /* Get the raw ELF section contents for libctf.  */
-  ctf_scn = elf_helpers::find_section(ctxt->elf_handler, ".ctf", SHT_PROGBITS);
+  const char *ctf_name = ".ctf";
+  ctf_scn = elf_helpers::find_section_by_name(ctxt->elf_handler, ctf_name);
+  if (ctf_scn == NULL)
+    {
+      if (ctf_dbg_scn)
+        ctf_scn = ctf_dbg_scn;
+      else
+        {
+          status |= elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
+          return;
+        }
+    }
 
   // ET_{EXEC,DYN} needs .dyn{sym,str} in ctf_arc_bufopen
   const char *symtab_name = ".dynsym";
@@ -1403,15 +1502,17 @@ slurp_elf_info(read_context *ctxt, corpus_sptr corp)
 
   symtab_scn = elf_helpers::find_section_by_name(ctxt->elf_handler, symtab_name);
   strtab_scn = elf_helpers::find_section_by_name(ctxt->elf_handler, strtab_name);
-
-  if (ctf_scn == NULL || symtab_scn == NULL || strtab_scn == NULL)
-    return 0;
+  if (symtab_scn == NULL || strtab_scn == NULL)
+    {
+      status |= elf_reader::STATUS_NO_SYMBOLS_FOUND;
+      return;
+    }
 
   fill_ctf_section(ctf_scn, &ctxt->ctf_sect);
   fill_ctf_section(symtab_scn, &ctxt->symtab_sect);
   fill_ctf_section(strtab_scn, &ctxt->strtab_sect);
 
-  return 1;
+  status |= elf_reader::STATUS_OK;
 }
 
 /// Create and return a new read context to process CTF information
@@ -1422,9 +1523,12 @@ slurp_elf_info(read_context *ctxt, corpus_sptr corp)
 
 read_context_sptr
 create_read_context(const std::string& elf_path,
+                    const vector<char**>& debug_info_root_paths,
                     ir::environment *env)
 {
-  read_context_sptr result(new read_context(elf_path, env));
+  read_context_sptr result(new read_context(elf_path,
+                                            debug_info_root_paths,
+                                            env));
   return result;
 }
 
@@ -1443,17 +1547,12 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
 {
   corpus_sptr corp
     = std::make_shared<corpus>(ctxt->ir_env, ctxt->filename);
-
   ctxt->cur_corpus_ = corp;
-  /* Be optimist.  */
-  status = elf_reader::STATUS_OK;
+  status = elf_reader::STATUS_UNKNOWN;
 
   /* Open the ELF file.  */
   if (!open_elf_handler(ctxt))
-    {
-      status = elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
       return corp;
-    }
 
   bool is_linux_kernel = elf_helpers::is_linux_kernel(ctxt->elf_handler);
   corpus::origin origin = corpus::CTF_ORIGIN;
@@ -1465,11 +1564,11 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
   if (ctxt->cur_corpus_group_)
     ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
 
-  if (!slurp_elf_info(ctxt, corp) && !is_linux_kernel)
-    {
-      status = elf_reader::STATUS_NO_SYMBOLS_FOUND;
+  slurp_elf_info(ctxt, corp, status);
+  if (!is_linux_kernel
+      && ((status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND) |
+          (status & elf_reader::STATUS_NO_SYMBOLS_FOUND)))
       return corp;
-    }
 
   // Set the set of exported declaration that are defined.
   ctxt->exported_decls_builder
@@ -1496,7 +1595,7 @@ read_corpus(read_context *ctxt, elf_reader::status &status)
 
   ctxt->ir_env->canonicalization_is_done(false);
   if (ctxt->ctfa == NULL)
-    status = elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
+    status |= elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
   else
     {
       process_ctf_archive(ctxt, corp);
@@ -1583,10 +1682,11 @@ read_and_add_corpus_to_group_from_elf(read_context* ctxt,
 void
 reset_read_context(read_context_sptr	&ctxt,
                    const std::string&	 elf_path,
+                   const vector<char**>& debug_info_root_path,
                    ir::environment*	 environment)
 {
   if (ctxt)
-    ctxt->initialize(elf_path, environment);
+    ctxt->initialize(elf_path, debug_info_root_path, environment);
 }
 
 /// Returns a key to be use in types_map dict conformed by
diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc
index a1fd4e6c..c41e339e 100644
--- a/src/abg-elf-helpers.cc
+++ b/src/abg-elf-helpers.cc
@@ -300,6 +300,8 @@ e_machine_to_string(GElf_Half e_machine)
 ///
 /// @param elf_handle the elf handle to use.
 ///
+/// @param name the section name.
+///
 /// @return the section found, nor nil if none was found.
 Elf_Scn*
 find_section_by_name(Elf* elf_handle, const std::string& name)
diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
index f30c3f1d..7ea7ecb7 100644
--- a/src/abg-tools-utils.cc
+++ b/src/abg-tools-utils.cc
@@ -2633,6 +2633,9 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
 /// @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.
 ///
@@ -2646,6 +2649,7 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
                               const string&       vmlinux,
                               vector<string>&     modules,
                               const string&       root,
+                              vector<char**>&     di_roots,
                               bool                verbose,
                               timer&              t,
                               environment_sptr&   env)
@@ -2655,7 +2659,7 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
 
   abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
   ctf_reader::read_context_sptr ctxt;
-  ctxt = ctf_reader::create_read_context(vmlinux, env.get());
+  ctxt = ctf_reader::create_read_context(vmlinux, di_roots, env.get());
   group.reset(new corpus_group(env.get(), root));
   set_read_context_corpus_group(*ctxt, group);
 
@@ -2690,7 +2694,7 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
          << "/" << total_nb_modules
          << ") ... " << std::flush;
 
-      reset_read_context(ctxt, *m, env.get());
+      reset_read_context(ctxt, *m, di_roots, env.get());
       set_read_context_corpus_group(*ctxt, group);
 
       t.start();
@@ -2788,7 +2792,8 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
                                       supprs, verbose, t, env);
 #ifdef WITH_CTF
       maybe_load_vmlinux_ctf_corpus(origin, group, vmlinux,
-                                    modules, root, verbose, t, env);
+                                    modules, root, di_roots,
+                                    verbose, t, env);
 #endif
     }
 
diff --git a/tests/test-read-ctf.cc b/tests/test-read-ctf.cc
index 215ed8d6..1f31e90c 100644
--- a/tests/test-read-ctf.cc
+++ b/tests/test-read-ctf.cc
@@ -22,6 +22,7 @@
 
 using std::string;
 using std::cerr;
+using std::vector;
 
 using abigail::tests::read_common::InOutSpec;
 using abigail::tests::read_common::test_task;
@@ -346,9 +347,11 @@ test_task_ctf::perform()
   env.reset(new abigail::ir::environment);
   abigail::elf_reader::status status =
     abigail::elf_reader::STATUS_UNKNOWN;
+  vector<char**> di_roots;
   ABG_ASSERT(abigail::tools_utils::file_exists(in_elf_path));
 
   read_context_sptr ctxt = create_read_context(in_elf_path,
+                                               di_roots,
                                                env.get());
   ABG_ASSERT(ctxt);
 
diff --git a/tools/abidiff.cc b/tools/abidiff.cc
index 763f084e..37a273ad 100644
--- a/tools/abidiff.cc
+++ b/tools/abidiff.cc
@@ -247,7 +247,9 @@ display_usage(const string& prog_name, ostream& out)
     << " --dump-diff-tree  emit a debug dump of the internal diff tree to "
     "the error output stream\n"
     <<  " --stats  show statistics about various internal stuff\n"
-    << "  --ctf use CTF instead of DWARF in ELF files\n"
+#ifdef WITH_CTF
+    << " --ctf use CTF instead of DWARF in ELF files\n"
+#endif
 #ifdef WITH_DEBUG_SELF_COMPARISON
     << " --debug debug the process of comparing an ABI corpus against itself"
 #endif
@@ -1184,6 +1186,7 @@ main(int argc, char* argv[])
               {
                 abigail::ctf_reader::read_context_sptr ctxt
                   = abigail::ctf_reader::create_read_context(opts.file1,
+                                                             opts.prepared_di_root_paths1,
                                                              env.get());
                 ABG_ASSERT(ctxt);
                 c1 = abigail::ctf_reader::read_corpus(ctxt.get(),
@@ -1267,6 +1270,7 @@ main(int argc, char* argv[])
               {
                 abigail::ctf_reader::read_context_sptr ctxt
                   = abigail::ctf_reader::create_read_context(opts.file2,
+                                                             opts.prepared_di_root_paths2,
                                                              env.get());
                 ABG_ASSERT(ctxt);
                 c2 = abigail::ctf_reader::read_corpus(ctxt.get(),
diff --git a/tools/abidw.cc b/tools/abidw.cc
index 32d055f5..1ca642bb 100644
--- a/tools/abidw.cc
+++ b/tools/abidw.cc
@@ -540,9 +540,9 @@ load_corpus_and_write_abixml(char* argv[],
   if (opts.use_ctf)
     {
       abigail::ctf_reader::read_context_sptr ctxt
-        = abigail::ctf_reader::create_read_context (opts.in_file_path,
-                                                    env.get());
-
+        = abigail::ctf_reader::create_read_context(opts.in_file_path,
+                                                   opts.prepared_di_root_paths,
+                                                   env.get());
       assert (ctxt);
       t.start();
       corp = abigail::ctf_reader::read_corpus (ctxt, s);
diff --git a/tools/abilint.cc b/tools/abilint.cc
index 4883b557..b45cad19 100644
--- a/tools/abilint.cc
+++ b/tools/abilint.cc
@@ -782,9 +782,10 @@ main(int argc, char* argv[])
 #ifdef WITH_CTF
             if (opts.use_ctf)
               {
-                abigail::ctf_reader::read_context_sptr ctxt
-                  = abigail::ctf_reader::create_read_context(opts.file_path,
-                                                             env.get());
+                abigail::ctf_reader::read_context_sptr ctxt =
+                  abigail::ctf_reader::create_read_context(opts.file_path,
+                                                           di_roots,
+                                                           env.get());
                 ABG_ASSERT(ctxt);
                 corp = abigail::ctf_reader::read_corpus(ctxt.get(), s);
               }
diff --git a/tools/abipkgdiff.cc b/tools/abipkgdiff.cc
index eabd19ae..5efea651 100644
--- a/tools/abipkgdiff.cc
+++ b/tools/abipkgdiff.cc
@@ -1325,6 +1325,7 @@ compare(const elf_file& elf1,
     if (opts.use_ctf)
       {
         ctxt_ctf = abigail::ctf_reader::create_read_context(elf1.path,
+							    di_dirs1,
                                                             env.get());
         ABG_ASSERT(ctxt_ctf);
         corpus1 = abigail::ctf_reader::read_corpus(ctxt_ctf.get(),
@@ -1429,6 +1430,7 @@ compare(const elf_file& elf1,
     if (opts.use_ctf)
       {
         ctxt_ctf = abigail::ctf_reader::create_read_context(elf2.path,
+							    di_dirs2,
 							    env.get());
         corpus2 = abigail::ctf_reader::read_corpus(ctxt_ctf.get(),
                                                    c2_status);
@@ -1602,6 +1604,7 @@ compare_to_self(const elf_file& elf,
     if (opts.use_ctf)
       {
         ctxt_ctf = abigail::ctf_reader::create_read_context(elf.path,
+							    di_dirs,
                                                             env.get());
         ABG_ASSERT(ctxt_ctf);
         corp = abigail::ctf_reader::read_corpus(ctxt_ctf.get(),
  
Guillermo E. Martinez May 17, 2022, 3:13 p.m. UTC | #2
On Tuesday, May 17, 2022 9:33:43 AM CDT Dodji Seketeli wrote:
> Hello,
Hello Dodji,
> "Guillermo E. Martinez via Libabigail" <libabigail@sourceware.org> a
> écrit:
> 
> 
> > When an ELF `stripped' file is used to get CTF debug information the ELF
> > symbols used by ctf reader (`symtab_reader::symtab') is split in a
> > separate file and even though CTF was designed to be in ELF file after
> > be `stripped' this .ctf section can be 'loaded'  from and external
> > .debug file, for instance the script `find-debuginfo' used to generate
> > RPM debug packages split debug information in .debug files. The location
> > of such files is pass as a standard argument from libabigail tools and
> > the name of the file is gathering from the `.gnu_debuglink' section.
> >
> > 	* include/abg-ctf-reader.h (ctf_reader::create_read_context):
> > 	Add `debug_info_root_paths' argument.
> > 	(ctf_reader::reset_read_context): Likewise.
> > 	* src/abg-ctf-reader.cc: Add `read_context::elf_{handler,fd}_dbg',
> > 	data members.
> > 	(read_context::read_context): Add new `debug_info_root_paths'
> > 	argument.
> > 	(read_context::initialize): Likewise.
> > 	(ctf_reader::create_read_context): Likewise.
> > 	(ctf_reader::close_elf_handler): Release
> > 	`read_context::elf_{handler,fd}_dbg' members.
> > 	(ctf_reader::find_alt_debuginfo): Add new function.
> > 	(ctf_reader::slurp_elf_info): Add new argument `status'. Use
> > 	`find_alt_debuginfo' and `elf_helpers::find_section_by_name'
> > 	to read the symtab and ctf information from an external .debug
> > 	file, the `status' reference is updated.
> > 	(ctf_reader::read_corpus): Verify `status' after `slurp_elf_info'.
> > 	(ctf_reader::reset_read_context): Add new `debug_info_root_path'
> > 	argument.
> > 	* src/abg-elf-helpers.cc (elf_helpers::find_section_by_name): Update
> > 	comment.
> > 	* src/abg-tools-utils.cc (maybe_load_vmlinux_ctf_corpus):
> > 	Adjust `ctf_reader::{create,reset}_read_context'.
> > 	* tests/test-read-ctf.cc: Likewise.
> > 	* tools/abidiff.cc (display_usage): Add `--ctf' command line
> > 	option.
> > 	(main): Adjust `ctf_reader::create_read_context'.
> > 	Likewise.
> > 	* tools/abidw.cc (load_corpus_and_write_abixml): Adjust
> > 	`ctf_reader::create_read_context'.
> > 	* tools/abilint.cc: Likewise.
> 
> I have also adjusted the use of the ctf reader in abipkgdiff.
> 
> Please find below the resulting patch that was applied to master.
> Thanks!
Thanks to you!!
> 
> >
> > Signed-off-by: Guillermo E. Martinez <guillermo.e.martinez@oracle.com>
> 
> Applied to master.
> 
> [...]
> 
> From 1ebd5ff0eb09e6fe78d45065d3bb9bb02468d37c Mon Sep 17 00:00:00 2001
> From: "Guillermo E. Martinez" <guillermo.e.martinez@oracle.com>
> Date: Mon, 16 May 2022 13:32:54 -0500
> Subject: [PATCH] ctf-reader: add support to looking debug information in
>  external path
> [...]
guillermo
  

Patch

diff --git a/include/abg-ctf-reader.h b/include/abg-ctf-reader.h
index ba7289aa..60f3623d 100644
--- a/include/abg-ctf-reader.h
+++ b/include/abg-ctf-reader.h
@@ -31,6 +31,7 @@  typedef shared_ptr<read_context> read_context_sptr;
 
 read_context_sptr
 create_read_context(const std::string& elf_path,
+                    const vector<char**>& debug_info_root_paths,
                     ir::environment *env);
 corpus_sptr
 read_corpus(read_context *ctxt, elf_reader::status& status);
@@ -47,6 +48,7 @@  set_read_context_corpus_group(read_context& ctxt, corpus_group_sptr& group);
 void
 reset_read_context(read_context_sptr &ctxt,
                    const std::string&	elf_path,
+                   const vector<char**>& debug_info_root_path,
                    ir::environment*	environment);
 std::string
 dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type);
diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 89dea276..2bb3d924 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -70,6 +70,10 @@  public:
   Elf *elf_handler;
   int elf_fd;
 
+  /// libelf handler for the ELF file from which we read the CTF data,
+  /// and the corresponding file descriptor found in external .debug file
+  Elf *elf_handler_dbg;
+  int elf_fd_dbg;
 
   /// The symtab read from the ELF file.
   symtab_reader::symtab_sptr symtab;
@@ -83,6 +87,8 @@  public:
   corpus_sptr			cur_corpus_;
   corpus_group_sptr		cur_corpus_group_;
   corpus::exported_decls_builder* exported_decls_builder_;
+  // The set of directories under which to look for debug info.
+  vector<char**>		debug_info_root_paths_;
 
   /// Setter of the exported decls builder object.
   ///
@@ -253,15 +259,20 @@  public:
   ///
   /// @param elf_path the path to the ELF file.
   ///
-  /// @param environment the environment used by the current context.
+  /// @param debug_info_root_paths vector with the paths
+  /// to directories where .debug file is located.
+  ///
+  /// @param env the environment used by the current context.
   /// This environment contains resources needed by the reader and by
   /// the types and declarations that are to be created later.  Note
   /// that ABI artifacts that are to be compared all need to be
   /// created within the same environment.
-  read_context(const string& elf_path, ir::environment *env) :
-    ctfa(NULL)
+  read_context(const string& elf_path,
+               const vector<char**>& debug_info_root_paths,
+               ir::environment *env) :
+   ctfa(NULL)
   {
-    initialize(elf_path, env);
+    initialize(elf_path, debug_info_root_paths, env);
   }
 
   /// Initializer of read_context.
@@ -269,6 +280,9 @@  public:
   /// @param elf_path the path to the elf file the context is to be
   /// used for.
   ///
+  /// @param debug_info_root_paths vector with the paths
+  /// to directories where .debug file is located.
+  ///
   /// @param environment the environment used by the current context.
   /// This environment contains resources needed by the reader and by
   /// the types and declarations that are to be created later.  Note
@@ -279,16 +293,22 @@  public:
   /// must be greater than the life time of the resulting @ref
   /// read_context the context uses resources that are allocated in
   /// the environment.
-  void initialize(const string& elf_path, ir::environment *env)
+  void
+  initialize(const string& elf_path,
+             const vector<char**>& debug_info_root_paths,
+             ir::environment *env)
   {
     types_map.clear();
     filename = elf_path;
     ir_env = env;
     elf_handler = NULL;
+    elf_handler_dbg = NULL;
     elf_fd = -1;
+    elf_fd_dbg = -1;
     symtab.reset();
     cur_corpus_group_.reset();
     exported_decls_builder_ = 0;
+    debug_info_root_paths_ = debug_info_root_paths;
   }
 
   ~read_context()
@@ -1332,6 +1352,10 @@  close_elf_handler (read_context *ctxt)
   /* Finish the ELF handler and close the associated file.  */
   elf_end(ctxt->elf_handler);
   close(ctxt->elf_fd);
+
+  /* Finish the ELF handler and close the associated debug file.  */
+  elf_end(ctxt->elf_handler_dbg);
+  close(ctxt->elf_fd_dbg);
 }
 
 /// Fill a CTF section description with the information in a given ELF
@@ -1358,38 +1382,113 @@  fill_ctf_section(Elf_Scn *elf_section, ctf_sect_t *ctf_section)
   ctf_section->cts_entsize = section_header->sh_entsize;
 }
 
+/// Find a CTF section and debug symbols in a given ELF using
+/// .gnu_debuglink section.
+///
+/// @param ctxt the read context.
+/// @param ctf_dbg_section the CTF section to fill with the raw data.
+static void
+find_alt_debuginfo(read_context *ctxt, Elf_Scn **ctf_dbg_scn)
+{
+  std::string name;
+  Elf_Data *data;
+
+  Elf_Scn *section = elf_helpers::find_section
+    (ctxt->elf_handler, ".gnu_debuglink", SHT_PROGBITS);
+
+  if (section
+      && (data = elf_getdata(section, NULL))
+      && data->d_size != 0)
+    name = (char *) data->d_buf;
+
+  int fd = -1;
+  Elf *hdlr = NULL;
+  *ctf_dbg_scn = NULL;
+
+  if (!name.empty())
+    for (vector<char**>::const_iterator i = ctxt->debug_info_root_paths_.begin();
+         i != ctxt->debug_info_root_paths_.end();
+         ++i)
+      {
+        std::string file_path;
+        if (!tools_utils::find_file_under_dir(**i, name, file_path))
+          continue;
+
+        if ((fd = open(file_path.c_str(), O_RDONLY)) == -1)
+          continue;
+
+        if ((hdlr = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
+          {
+            close(fd);
+            continue;
+          }
+
+        ctxt->symtab =
+          symtab_reader::symtab::load(hdlr, ctxt->ir_env, nullptr);
+
+        // unlikely .ctf was designed to be present in stripped file
+        *ctf_dbg_scn =
+          elf_helpers::find_section(hdlr, ".ctf", SHT_PROGBITS);
+          break;
+
+        elf_end(hdlr);
+        close(fd);
+      }
+
+  // If we don't have a symbol table, use current one in ELF file
+  if (!ctxt->symtab)
+    ctxt->symtab =
+     symtab_reader::symtab::load(ctxt->elf_handler, ctxt->ir_env, nullptr);
+
+  ctxt->elf_handler_dbg = hdlr;
+  ctxt->elf_fd_dbg = fd;
+}
+
 /// Slurp certain information from the ELF file described by a given
 /// read context and install it in a libabigail corpus.
 ///
 /// @param ctxt the read context
 /// @param corp the libabigail corpus in which to install the info.
-///
-/// @return 0 if there is an error.
-/// @return 1 otherwise.
-
-static int
-slurp_elf_info(read_context *ctxt, corpus_sptr corp)
+/// @param status the resulting status flags.
+static void
+slurp_elf_info(read_context *ctxt,
+               corpus_sptr corp,
+               elf_reader::status& status)
 {
+  /* Set the ELF architecture.  */
+  GElf_Ehdr *ehdr, eh_mem;
   Elf_Scn *symtab_scn;
-  Elf_Scn *ctf_scn;
+  Elf_Scn *ctf_scn, *ctf_dbg_scn;
   Elf_Scn *strtab_scn;
-  GElf_Ehdr eh_mem;
-  GElf_Ehdr *ehdr = gelf_getehdr(ctxt->elf_handler, &eh_mem);
 
-  /* Set the ELF architecture.  */
+  if (!(ehdr = gelf_getehdr(ctxt->elf_handler, &eh_mem)))
+      return;
+
   corp->set_architecture_name(elf_helpers::e_machine_to_string(ehdr->e_machine));
 
-  /* Read the symtab from the ELF file and set it in the corpus.  */
-  ctxt->symtab =
-    symtab_reader::symtab::load(ctxt->elf_handler, ctxt->ir_env,
-                                0 /* No suppressions.  */);
+  find_alt_debuginfo(ctxt, &ctf_dbg_scn);
+  ABG_ASSERT(ctxt->symtab);
   corp->set_symtab(ctxt->symtab);
 
   if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
-    return 1;
+    {
+      status |= elf_reader::STATUS_OK;
+      return;
+    }
 
   /* Get the raw ELF section contents for libctf.  */
-  ctf_scn = elf_helpers::find_section(ctxt->elf_handler, ".ctf", SHT_PROGBITS);
+  const char *ctf_name = ".ctf";
+  ctf_scn = elf_helpers::find_section_by_name(ctxt->elf_handler, ctf_name);
+  if (ctf_scn == NULL)
+    {
+      if (ctf_dbg_scn)
+        ctf_scn = ctf_dbg_scn;
+      else
+        {
+          status |= elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
+          return;
+        }
+    }
 
   // ET_{EXEC,DYN} needs .dyn{sym,str} in ctf_arc_bufopen
   const char *symtab_name = ".dynsym";
@@ -1403,15 +1502,17 @@  slurp_elf_info(read_context *ctxt, corpus_sptr corp)
 
   symtab_scn = elf_helpers::find_section_by_name(ctxt->elf_handler, symtab_name);
   strtab_scn = elf_helpers::find_section_by_name(ctxt->elf_handler, strtab_name);
-
-  if (ctf_scn == NULL || symtab_scn == NULL || strtab_scn == NULL)
-    return 0;
+  if (symtab_scn == NULL || strtab_scn == NULL)
+    {
+      status |= elf_reader::STATUS_NO_SYMBOLS_FOUND;
+      return;
+    }
 
   fill_ctf_section(ctf_scn, &ctxt->ctf_sect);
   fill_ctf_section(symtab_scn, &ctxt->symtab_sect);
   fill_ctf_section(strtab_scn, &ctxt->strtab_sect);
 
-  return 1;
+  status |= elf_reader::STATUS_OK;
 }
 
 /// Create and return a new read context to process CTF information
@@ -1422,9 +1523,12 @@  slurp_elf_info(read_context *ctxt, corpus_sptr corp)
 
 read_context_sptr
 create_read_context(const std::string& elf_path,
+                    const vector<char**>& debug_info_root_paths,
                     ir::environment *env)
 {
-  read_context_sptr result(new read_context(elf_path, env));
+  read_context_sptr result(new read_context(elf_path,
+                                            debug_info_root_paths,
+                                            env));
   return result;
 }
 
@@ -1443,17 +1547,12 @@  read_corpus(read_context *ctxt, elf_reader::status &status)
 {
   corpus_sptr corp
     = std::make_shared<corpus>(ctxt->ir_env, ctxt->filename);
-
   ctxt->cur_corpus_ = corp;
-  /* Be optimist.  */
-  status = elf_reader::STATUS_OK;
+  status = elf_reader::STATUS_UNKNOWN;
 
   /* Open the ELF file.  */
   if (!open_elf_handler(ctxt))
-    {
-      status = elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
       return corp;
-    }
 
   bool is_linux_kernel = elf_helpers::is_linux_kernel(ctxt->elf_handler);
   corpus::origin origin = corpus::CTF_ORIGIN;
@@ -1465,11 +1564,11 @@  read_corpus(read_context *ctxt, elf_reader::status &status)
   if (ctxt->cur_corpus_group_)
     ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
 
-  if (!slurp_elf_info(ctxt, corp) && !is_linux_kernel)
-    {
-      status = elf_reader::STATUS_NO_SYMBOLS_FOUND;
+  slurp_elf_info(ctxt, corp, status);
+  if (!is_linux_kernel
+      && ((status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND) |
+          (status & elf_reader::STATUS_NO_SYMBOLS_FOUND)))
       return corp;
-    }
 
   // Set the set of exported declaration that are defined.
   ctxt->exported_decls_builder
@@ -1496,7 +1595,7 @@  read_corpus(read_context *ctxt, elf_reader::status &status)
 
   ctxt->ir_env->canonicalization_is_done(false);
   if (ctxt->ctfa == NULL)
-    status = elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
+    status |= elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
   else
     {
       process_ctf_archive(ctxt, corp);
@@ -1583,10 +1682,11 @@  read_and_add_corpus_to_group_from_elf(read_context* ctxt,
 void
 reset_read_context(read_context_sptr	&ctxt,
                    const std::string&	 elf_path,
+                   const vector<char**>& debug_info_root_path,
                    ir::environment*	 environment)
 {
   if (ctxt)
-    ctxt->initialize(elf_path, environment);
+    ctxt->initialize(elf_path, debug_info_root_path, environment);
 }
 
 /// Returns a key to be use in types_map dict conformed by
diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc
index a1fd4e6c..c41e339e 100644
--- a/src/abg-elf-helpers.cc
+++ b/src/abg-elf-helpers.cc
@@ -300,6 +300,8 @@  e_machine_to_string(GElf_Half e_machine)
 ///
 /// @param elf_handle the elf handle to use.
 ///
+/// @param name the section name.
+///
 /// @return the section found, nor nil if none was found.
 Elf_Scn*
 find_section_by_name(Elf* elf_handle, const std::string& name)
diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
index f30c3f1d..7ea7ecb7 100644
--- a/src/abg-tools-utils.cc
+++ b/src/abg-tools-utils.cc
@@ -2633,6 +2633,9 @@  maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
 /// @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.
 ///
@@ -2646,6 +2649,7 @@  maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
                               const string&       vmlinux,
                               vector<string>&     modules,
                               const string&       root,
+                              vector<char**>&     di_roots,
                               bool                verbose,
                               timer&              t,
                               environment_sptr&   env)
@@ -2655,7 +2659,7 @@  maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
 
   abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
   ctf_reader::read_context_sptr ctxt;
-  ctxt = ctf_reader::create_read_context(vmlinux, env.get());
+  ctxt = ctf_reader::create_read_context(vmlinux, di_roots, env.get());
   group.reset(new corpus_group(env.get(), root));
   set_read_context_corpus_group(*ctxt, group);
 
@@ -2690,7 +2694,7 @@  maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
          << "/" << total_nb_modules
          << ") ... " << std::flush;
 
-      reset_read_context(ctxt, *m, env.get());
+      reset_read_context(ctxt, *m, di_roots, env.get());
       set_read_context_corpus_group(*ctxt, group);
 
       t.start();
@@ -2788,7 +2792,8 @@  build_corpus_group_from_kernel_dist_under(const string&	root,
                                       supprs, verbose, t, env);
 #ifdef WITH_CTF
       maybe_load_vmlinux_ctf_corpus(origin, group, vmlinux,
-                                    modules, root, verbose, t, env);
+                                    modules, root, di_roots,
+                                    verbose, t, env);
 #endif
     }
 
diff --git a/tests/test-read-ctf.cc b/tests/test-read-ctf.cc
index 215ed8d6..1f31e90c 100644
--- a/tests/test-read-ctf.cc
+++ b/tests/test-read-ctf.cc
@@ -22,6 +22,7 @@ 
 
 using std::string;
 using std::cerr;
+using std::vector;
 
 using abigail::tests::read_common::InOutSpec;
 using abigail::tests::read_common::test_task;
@@ -346,9 +347,11 @@  test_task_ctf::perform()
   env.reset(new abigail::ir::environment);
   abigail::elf_reader::status status =
     abigail::elf_reader::STATUS_UNKNOWN;
+  vector<char**> di_roots;
   ABG_ASSERT(abigail::tools_utils::file_exists(in_elf_path));
 
   read_context_sptr ctxt = create_read_context(in_elf_path,
+                                               di_roots,
                                                env.get());
   ABG_ASSERT(ctxt);
 
diff --git a/tools/abidiff.cc b/tools/abidiff.cc
index 763f084e..37a273ad 100644
--- a/tools/abidiff.cc
+++ b/tools/abidiff.cc
@@ -247,7 +247,9 @@  display_usage(const string& prog_name, ostream& out)
     << " --dump-diff-tree  emit a debug dump of the internal diff tree to "
     "the error output stream\n"
     <<  " --stats  show statistics about various internal stuff\n"
-    << "  --ctf use CTF instead of DWARF in ELF files\n"
+#ifdef WITH_CTF
+    << " --ctf use CTF instead of DWARF in ELF files\n"
+#endif
 #ifdef WITH_DEBUG_SELF_COMPARISON
     << " --debug debug the process of comparing an ABI corpus against itself"
 #endif
@@ -1184,6 +1186,7 @@  main(int argc, char* argv[])
               {
                 abigail::ctf_reader::read_context_sptr ctxt
                   = abigail::ctf_reader::create_read_context(opts.file1,
+                                                             opts.prepared_di_root_paths1,
                                                              env.get());
                 ABG_ASSERT(ctxt);
                 c1 = abigail::ctf_reader::read_corpus(ctxt.get(),
@@ -1267,6 +1270,7 @@  main(int argc, char* argv[])
               {
                 abigail::ctf_reader::read_context_sptr ctxt
                   = abigail::ctf_reader::create_read_context(opts.file2,
+                                                             opts.prepared_di_root_paths2,
                                                              env.get());
                 ABG_ASSERT(ctxt);
                 c2 = abigail::ctf_reader::read_corpus(ctxt.get(),
diff --git a/tools/abidw.cc b/tools/abidw.cc
index 32d055f5..1ca642bb 100644
--- a/tools/abidw.cc
+++ b/tools/abidw.cc
@@ -540,9 +540,9 @@  load_corpus_and_write_abixml(char* argv[],
   if (opts.use_ctf)
     {
       abigail::ctf_reader::read_context_sptr ctxt
-        = abigail::ctf_reader::create_read_context (opts.in_file_path,
-                                                    env.get());
-
+        = abigail::ctf_reader::create_read_context(opts.in_file_path,
+                                                   opts.prepared_di_root_paths,
+                                                   env.get());
       assert (ctxt);
       t.start();
       corp = abigail::ctf_reader::read_corpus (ctxt, s);
diff --git a/tools/abilint.cc b/tools/abilint.cc
index 4883b557..b45cad19 100644
--- a/tools/abilint.cc
+++ b/tools/abilint.cc
@@ -782,9 +782,10 @@  main(int argc, char* argv[])
 #ifdef WITH_CTF
             if (opts.use_ctf)
               {
-                abigail::ctf_reader::read_context_sptr ctxt
-                  = abigail::ctf_reader::create_read_context(opts.file_path,
-                                                             env.get());
+                abigail::ctf_reader::read_context_sptr ctxt =
+                  abigail::ctf_reader::create_read_context(opts.file_path,
+                                                           di_roots,
+                                                           env.get());
                 ABG_ASSERT(ctxt);
                 corp = abigail::ctf_reader::read_corpus(ctxt.get(), s);
               }