diff --git a/configure.ac b/configure.ac
index 950e2704..4f835d07 100644
--- a/configure.ac
+++ b/configure.ac
@@ -144,6 +144,13 @@ AC_ARG_ENABLE(ubsan,
 	      ENABLE_UBSAN=$enableval,
 	      ENABLE_UBSAN=no)
 
+dnl check if user has enabled CTF code
+AC_ARG_ENABLE(ctf,
+	      AS_HELP_STRING([--enable-ctf=yes|no],
+			     [disable support of ctf files)]),
+	      ENABLE_CTF=$enableval,
+	      ENABLE_CTF=no)
+
 dnl *************************************************
 dnl check for dependencies
 dnl *************************************************
@@ -250,6 +257,24 @@ fi
 AC_SUBST(DW_LIBS)
 AC_SUBST([ELF_LIBS])
 
+dnl check for libctf presence if CTF code has been enabled by command line
+dnl argument, and then define CTF flag (to build CTF file code) if libctf is
+dnl found on the system
+CTF_LIBS=
+if test x$ENABLE_CTF = xyes; then
+  LIBCTF=
+  AC_CHECK_LIB(ctf, ctf_open, [LIBCTF=yes], [LIBCTF=no])
+  if test x$LIBCTF = xyes; then
+    AC_MSG_NOTICE([activating CTF code])
+    AC_DEFINE([WITH_CTF], 1,
+	     [Defined if user enables and system has the libctf library])
+    CTF_LIBS=-lctf
+  else
+    AC_MSG_NOTICE([CTF enabled but no libctf found])
+    ENABLE_CTF=no
+  fi
+fi
+
 dnl Check for dependency: libxml
 LIBXML2_VERSION=2.6.22
 PKG_CHECK_MODULES(XML, libxml-2.0 >= $LIBXML2_VERSION)
@@ -611,7 +636,7 @@ AX_VALGRIND_CHECK
 
 dnl Set the list of libraries libabigail depends on
 
-DEPS_LIBS="$XML_LIBS $ELF_LIBS $DW_LIBS"
+DEPS_LIBS="$XML_LIBS $ELF_LIBS $DW_LIBS $CTF_LIBS"
 AC_SUBST(DEPS_LIBS)
 
 if test x$ABIGAIL_DEVEL != x; then
@@ -649,6 +674,10 @@ if test x$ENABLE_UBSAN = xyes; then
     CXXFLAGS="$CXXFLAGS -fsanitize=undefined"
 fi
 
+dnl Set a few Automake conditionals
+
+AM_CONDITIONAL([CTF_READER],[test "x$ENABLE_CTF" = "xyes"])
+
 dnl Set the level of C++ standard we use.
 CXXFLAGS="$CXXFLAGS -std=$CXX_STANDARD"
 
@@ -955,6 +984,7 @@ AC_MSG_NOTICE([
     Enable bash completion	                   : ${ENABLE_BASH_COMPLETION}
     Enable fedabipkgdiff                           : ${ENABLE_FEDABIPKGDIFF}
     Enable python 3				   : ${ENABLE_PYTHON3}
+    Enable CTF front-end                           : ${ENABLE_CTF}
     Enable running tests under Valgrind            : ${enable_valgrind}
     Enable build with -fsanitize=address    	   : ${ENABLE_ASAN}
     Enable build with -fsanitize=memory    	   : ${ENABLE_MSAN}
diff --git a/doc/manuals/abidiff.rst b/doc/manuals/abidiff.rst
index 07053d6e..b37ed17e 100644
--- a/doc/manuals/abidiff.rst
+++ b/doc/manuals/abidiff.rst
@@ -500,6 +500,11 @@ Options
     changes.  Added or removed functions and variables do not have any
     diff nodes tree associated to them.
 
+  * ``--ctf``
+
+    When comparing binaries, extract ABI information from CTF debug
+    information, if present.
+
   * ``--stats``
 
     Emit statistics about various internal things.
diff --git a/doc/manuals/abilint.rst b/doc/manuals/abilint.rst
index 4cc0b428..4213a22e 100644
--- a/doc/manuals/abilint.rst
+++ b/doc/manuals/abilint.rst
@@ -90,5 +90,10 @@ Options
 
     Expect the input XML to represent a single translation unit.
 
+  * ``--ctf``
+
+    Extract ABI information from CTF debug information, if present in
+    the given object.
+
 .. _ELF: http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
 .. _DWARF: http://www.dwarfstd.org
diff --git a/include/Makefile.am b/include/Makefile.am
index 0f3b0936..9e5e037b 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -27,4 +27,8 @@ abg-viz-dot.h		\
 abg-viz-svg.h		\
 abg-regex.h
 
+if CTF_READER
+pkginclude_HEADERS += abg-ctf-reader.h
+endif
+
 EXTRA_DIST = abg-version.h.in
diff --git a/include/abg-corpus.h b/include/abg-corpus.h
index 136c348c..652a8294 100644
--- a/include/abg-corpus.h
+++ b/include/abg-corpus.h
@@ -46,6 +46,7 @@ public:
     ARTIFICIAL_ORIGIN = 0,
     NATIVE_XML_ORIGIN,
     DWARF_ORIGIN,
+    CTF_ORIGIN,
     LINUX_KERNEL_BINARY_ORIGIN
   };
 
diff --git a/include/abg-ctf-reader.h b/include/abg-ctf-reader.h
new file mode 100644
index 00000000..07eccec6
--- /dev/null
+++ b/include/abg-ctf-reader.h
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// -*- Mode: C++ -*-
+//
+// Copyright (C) 2021 Oracle, Inc.
+//
+// Author: Jose E. Marchesi
+
+/// @file
+///
+/// This file contains the declarations of the entry points to
+/// de-serialize an instance of @ref abigail::corpus from a file in
+/// elf format, containing CTF information.
+
+#ifndef __ABG_CTF_READER_H__
+#define __ABG_CTF_READER_H__
+
+#include <ostream>
+#include "abg-corpus.h"
+#include "abg-suppression.h"
+
+namespace abigail
+{
+namespace ctf_reader
+{
+
+class read_context;
+read_context *create_read_context (std::string elf_path,
+                                   ir::environment *env);
+corpus_sptr read_corpus (read_context *ctxt);
+
+} // end namespace ctf_reader
+} // end namespace abigail
+
+#endif // ! __ABG_CTF_READER_H__
diff --git a/src/Makefile.am b/src/Makefile.am
index 430ce98d..b60d74cb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -41,6 +41,10 @@ abg-symtab-reader.h			\
 abg-symtab-reader.cc			\
 $(VIZ_SOURCES)
 
+if CTF_READER
+libabigail_la_SOURCES += abg-ctf-reader.cc
+endif
+
 libabigail_la_LIBADD = $(DEPS_LIBS)
 libabigail_la_LDFLAGS = -lpthread -Wl,--as-needed -no-undefined
 
diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
new file mode 100644
index 00000000..1c41ea02
--- /dev/null
+++ b/src/abg-ctf-reader.cc
@@ -0,0 +1,1032 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// -*- Mode: C++ -*-
+//
+// Copyright (C) 2021 Oracle, Inc.
+//
+// Author: Jose E. Marchesi
+
+/// @file
+///
+/// This file contains the definitions of the entry points to
+/// de-serialize an instance of @ref abigail::corpus from a file in
+/// ELF format, containing CTF information.
+
+#include "config.h"
+
+#include <fcntl.h> /* For open(3) */
+#include <iostream>
+
+#include "ctf-api.h"
+
+#include "abg-internal.h"
+#include "abg-ir-priv.h"
+#include "abg-elf-helpers.h"
+
+// <headers defining libabigail's API go under here>
+ABG_BEGIN_EXPORT_DECLARATIONS
+
+#include "abg-ctf-reader.h"
+#include "abg-libxml-utils.h"
+#include "abg-reader.h"
+#include "abg-corpus.h"
+#include "abg-symtab-reader.h"
+#include "abg-tools-utils.h"
+
+ABG_END_EXPORT_DECLARATIONS
+// </headers defining libabigail's API>
+
+namespace abigail
+{
+namespace ctf_reader
+{
+
+class read_context
+{
+public:
+  /// The name of the ELF file from which the CTF archive got
+  /// extracted.
+  string filename;
+
+  /// The IR environment.
+  ir::environment *ir_env;
+
+  /// The CTF archive read from FILENAME.  If an archive couldn't
+  /// be read from the file then this is NULL.
+  ctf_archive_t *ctfa;
+
+  /// A map associating CTF type ids with libabigail IR types.  This
+  /// is used to reuse already generated types.
+  unordered_map<ctf_id_t,type_base_sptr> types_map;
+
+  /// The symtab read from the ELF file.
+  symtab_reader::symtab_sptr symtab;
+
+  /// Associate a given CTF type ID with a given libabigail IR type.
+  void add_type(ctf_id_t ctf_type, type_base_sptr type)
+  {
+    types_map.insert(std::make_pair(ctf_type, type));
+  }
+
+  /// Lookup a given CTF type ID in the types map.
+  ///
+  /// @param ctf_type the type ID of the type to lookup.
+  type_base_sptr lookup_type(ctf_id_t ctf_type)
+  {
+    type_base_sptr result;
+
+    auto search = types_map.find(ctf_type);
+    if (search != types_map.end())
+      result = search->second;
+
+    return result;
+  }
+
+  /// Canonicalize all the types stored in the types map.
+  void canonicalize_all_types(void)
+  {
+    for (auto t = types_map.begin(); t != types_map.end(); t++)
+      canonicalize (t->second);
+  }
+
+  /// Constructor.
+  ///
+  /// @param elf_path the path to the ELF file.
+  read_context(string elf_path, ir::environment *env)
+  {
+    int err;
+
+    types_map.clear();
+    filename = elf_path;
+    ir_env = env;
+    ctfa = ctf_open(filename.c_str(), NULL /* BFD target */, &err);
+
+    if (ctfa == NULL)
+      fprintf(stderr, "cannot open %s: %s\n", filename.c_str(), ctf_errmsg(err));
+  }
+
+  /// Destructor of the @ref read_context type.
+  ~read_context()
+  {
+    ctf_close(ctfa);
+  }
+}; // end class read_context.
+
+/// Forward reference, needed because several of the process_ctf_*
+/// functions below are indirectly recursive through this call.
+static type_base_sptr lookup_type(read_context *ctxt,
+                                  corpus_sptr corp,
+                                  translation_unit_sptr tunit,
+                                  ctf_dict_t *ctf_dictionary,
+                                  ctf_id_t ctf_type);
+
+/// Build and return a typedef libabigail IR.
+///
+/// @param ctxt 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 typedef.
+
+static typedef_decl_sptr
+process_ctf_typedef(read_context *ctxt,
+                    corpus_sptr corp,
+                    translation_unit_sptr tunit,
+                    ctf_dict_t *ctf_dictionary,
+                    ctf_id_t ctf_type)
+{
+  typedef_decl_sptr result;
+
+  ctf_id_t ctf_utype = ctf_type_reference(ctf_dictionary, ctf_type);
+  if (ctf_utype == CTF_ERR)
+    return result;
+
+  const char *typedef_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
+  type_base_sptr utype = lookup_type(ctxt, corp, tunit,
+                                     ctf_dictionary, ctf_utype);
+
+  if (!utype)
+    return result;
+
+  result.reset(new typedef_decl(typedef_name, utype, location(),
+                                typedef_name /* mangled_name */));
+
+  /* If this typedef "names" an anonymous type, reflect this fact in
+     the underlying type.  In C enum, struct and union types can be
+     anonymous.  */
+  if (is_anonymous_type(utype)
+      && (is_enum_type(utype) || is_class_or_union_type(utype)))
+    {
+      decl_base_sptr decl = is_decl(utype);
+      ABG_ASSERT(decl);
+      decl->set_naming_typedef(result);
+    }
+
+  return result;
+}
+
+/// Build and return an integer or float type declaration libabigail
+/// IR.
+///
+/// @param ctxt 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.
+///
+/// @return a shared pointer to the IR node for the type.
+
+static type_decl_sptr
+process_ctf_base_type(read_context *ctxt,
+                      corpus_sptr corp,
+                      ctf_dict_t *ctf_dictionary,
+                      ctf_id_t ctf_type)
+{
+  type_decl_sptr result;
+
+  ssize_t type_alignment = ctf_type_align(ctf_dictionary, ctf_type);
+  const char *type_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
+
+  /* Get the type encoding and extract some useful properties of
+     the type from it.  In case of any error, just ignore the
+     type.  */
+  ctf_encoding_t type_encoding;
+  if (ctf_type_encoding(ctf_dictionary,
+                         ctf_type,
+                         &type_encoding))
+    return result;
+
+  /* Create the IR type corresponding to the CTF type.  */
+  if (type_encoding.cte_bits == 0
+      && type_encoding.cte_format == CTF_INT_SIGNED)
+    {
+      /* This is the `void' type.  */
+      type_base_sptr void_type = ctxt->ir_env->get_void_type();
+      decl_base_sptr type_declaration = get_type_declaration(void_type);
+      result = is_type_decl(type_declaration);
+    }
+  else
+    {
+      result = lookup_basic_type(type_name, *corp);
+      if (!result)
+        result.reset(new type_decl(ctxt->ir_env,
+                                   type_name,
+                                   type_encoding.cte_bits,
+                                   type_alignment * 8 /* in bits */,
+                                   location(),
+                                   type_name /* mangled_name */));
+
+    }
+
+  return result;
+}
+
+/// Build and return a function type libabigail IR.
+///
+/// @param ctxt 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 function type.
+
+static function_type_sptr
+process_ctf_function_type(read_context *ctxt,
+                          corpus_sptr corp,
+                          translation_unit_sptr tunit,
+                          ctf_dict_t *ctf_dictionary,
+                          ctf_id_t ctf_type)
+{
+  function_type_sptr result;
+
+  /* Fetch the function type info from the CTF type.  */
+  ctf_funcinfo_t funcinfo;
+  ctf_func_type_info(ctf_dictionary, ctf_type, &funcinfo);
+  int vararg_p = funcinfo.ctc_flags & CTF_FUNC_VARARG;
+
+  /* Take care first of the result type.  */
+  ctf_id_t ctf_ret_type = funcinfo.ctc_return;
+  type_base_sptr ret_type = lookup_type(ctxt, corp, tunit,
+                                        ctf_dictionary, ctf_ret_type);
+  if (!ret_type)
+    return result;
+
+  /* Now process the argument types.  */
+  int argc = funcinfo.ctc_argc;
+  std::vector<ctf_id_t> argv(argc);
+  if (static_cast<ctf_id_t>(ctf_func_type_args(ctf_dictionary, ctf_type,
+					       argc, argv.data())) == CTF_ERR)
+    return result;
+
+  function_decl::parameters function_parms;
+  for (int i = 0; i < argc; i++)
+    {
+      ctf_id_t ctf_arg_type = argv[i];
+      type_base_sptr arg_type = lookup_type(ctxt, corp, tunit,
+                                            ctf_dictionary, ctf_arg_type);
+      if (!arg_type)
+        return result;
+
+      function_decl::parameter_sptr parm
+        (new function_decl::parameter(arg_type, "",
+                                      location(),
+                                      vararg_p && (i == argc - 1),
+                                      false /* is_artificial */));
+      function_parms.push_back(parm);
+    }
+
+
+  /* Ok now the function type itself.  */
+  result.reset(new function_type(ret_type,
+                                 function_parms,
+                                 tunit->get_address_size(),
+                                 ctf_type_align(ctf_dictionary, ctf_type)));
+
+  tunit->bind_function_type_life_time(result);
+  result->set_is_artificial(true);
+  return result;
+}
+
+/// Add member information to a IR struct or union type.
+///
+/// @param ctxt 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(read_context *ctxt,
+                        corpus_sptr corp,
+                        translation_unit_sptr tunit,
+                        ctf_dict_t *ctf_dictionary,
+                        ctf_id_t ctf_type,
+                        class_or_union_sptr sou)
+{
+  ssize_t member_size;
+  ctf_next_t *member_next = NULL;
+  const char *member_name = NULL;
+  ctf_id_t member_ctf_type;
+
+  while ((member_size = ctf_member_next(ctf_dictionary, ctf_type,
+                                        &member_next, &member_name,
+                                        &member_ctf_type,
+                                        CTF_MN_RECURSE)) >= 0)
+    {
+      ctf_membinfo_t membinfo;
+
+      if (static_cast<ctf_id_t>(ctf_member_info(ctf_dictionary,
+						ctf_type,
+						member_name,
+						&membinfo)) == CTF_ERR)
+        return;
+
+      /* Build the IR for the member's type.  */
+      type_base_sptr member_type = lookup_type(ctxt, corp, tunit,
+                                               ctf_dictionary,
+                                               member_ctf_type);
+      if (!member_type)
+        /* Ignore this member.  */
+        continue;
+
+      /* Create a declaration IR node for the member and add it to the
+         struct type.  */
+      var_decl_sptr data_member_decl(new var_decl(member_name,
+                                                  member_type,
+                                                  location(),
+                                                  member_name));
+      sou->add_data_member(data_member_decl,
+                           public_access,
+                           true /* is_laid_out */,
+                           false /* is_static */,
+                           membinfo.ctm_offset);
+    }
+  if (ctf_errno(ctf_dictionary) != ECTF_NEXT_END)
+    fprintf(stderr, "ERROR from ctf_member_next\n");
+}
+
+/// Build and return a struct type libabigail IR.
+///
+/// @param ctxt 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 struct type.
+
+static class_decl_sptr
+process_ctf_struct_type(read_context *ctxt,
+                        corpus_sptr corp,
+                        translation_unit_sptr tunit,
+                        ctf_dict_t *ctf_dictionary,
+                        ctf_id_t ctf_type)
+{
+  class_decl_sptr result;
+  std::string struct_type_name = ctf_type_name_raw(ctf_dictionary,
+                                                 ctf_type);
+  bool struct_type_is_anonymous = (struct_type_name == "");
+
+  /* The libabigail IR encodes C struct types in `class' IR nodes.  */
+  result.reset(new class_decl(ctxt->ir_env,
+                              struct_type_name,
+                              ctf_type_size(ctf_dictionary, ctf_type) * 8,
+                              ctf_type_align(ctf_dictionary, ctf_type) * 8,
+                              true /* is_struct */,
+                              location(),
+                              decl_base::VISIBILITY_DEFAULT,
+                              struct_type_is_anonymous));
+  if (!result)
+    return result;
+
+  /* The C type system indirectly supports loops by the mean of
+     pointers to structs or unions.  Since some contained type can
+     refer to this struct, we have to make it available in the cache
+     at this point even if the members haven't been added to the IR
+     node yet.  */
+  ctxt->add_type(ctf_type, result);
+
+  /* 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(ctxt, corp, tunit, ctf_dictionary, ctf_type,
+                          result);
+
+  return result;
+}
+
+/// Build and return an union type libabigail IR.
+///
+/// @param ctxt 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 union type.
+
+static union_decl_sptr
+process_ctf_union_type(read_context *ctxt,
+                       corpus_sptr corp,
+                       translation_unit_sptr tunit,
+                       ctf_dict_t *ctf_dictionary,
+                       ctf_id_t ctf_type)
+{
+  union_decl_sptr result;
+  std::string union_type_name = ctf_type_name_raw(ctf_dictionary,
+                                                   ctf_type);
+  bool union_type_is_anonymous = (union_type_name == "");
+
+  /* Create the corresponding libabigail union IR node.  */
+  result.reset(new union_decl(ctxt->ir_env,
+                                union_type_name,
+                                ctf_type_size(ctf_dictionary, ctf_type) * 8,
+                                location(),
+                                decl_base::VISIBILITY_DEFAULT,
+                                union_type_is_anonymous));
+  if (!result)
+    return result;
+
+  /* The C type system indirectly supports loops by the mean of
+     pointers to structs or unions.  Since some contained type can
+     refer to this union, we have to make it available in the cache
+     at this point even if the members haven't been added to the IR
+     node yet.  */
+  ctxt->add_type(ctf_type, result);
+
+  /* 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(ctxt, corp, tunit, ctf_dictionary, ctf_type,
+                          result);
+
+  return result;
+}
+
+/// Build and return an array type libabigail IR.
+///
+/// @param ctxt 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(read_context *ctxt,
+                       corpus_sptr corp,
+                       translation_unit_sptr tunit,
+                       ctf_dict_t *ctf_dictionary,
+                       ctf_id_t ctf_type)
+{
+  array_type_def_sptr result;
+  ctf_arinfo_t ctf_ainfo;
+
+  /* First, get the information about the CTF array.  */
+  if (static_cast<ctf_id_t>(ctf_array_info(ctf_dictionary,
+					   ctf_type,
+					   &ctf_ainfo)) == CTF_ERR)
+    return result;
+
+  ctf_id_t ctf_element_type = ctf_ainfo.ctr_contents;
+  ctf_id_t ctf_index_type = ctf_ainfo.ctr_index;
+  uint64_t nelems = ctf_ainfo.ctr_nelems;
+
+  /* Make sure the element type is generated.  */
+  type_base_sptr element_type = lookup_type(ctxt, corp, tunit,
+                                            ctf_dictionary,
+                                            ctf_element_type);
+  if (!element_type)
+    return result;
+
+  /* Ditto for the index type.  */
+  type_base_sptr index_type = lookup_type(ctxt, corp, tunit,
+                                          ctf_dictionary,
+                                          ctf_index_type);
+  if (!index_type)
+    return result;
+
+  /* The number of elements of the array determines the IR subranges
+     type to build.  */
+  array_type_def::subranges_type subranges;
+  array_type_def::subrange_sptr subrange;
+  array_type_def::subrange_type::bound_value lower_bound;
+  array_type_def::subrange_type::bound_value upper_bound;
+
+  lower_bound.set_unsigned(0); /* CTF supports C only.  */
+  upper_bound.set_unsigned(nelems > 0 ? nelems - 1 : 0U);
+
+  subrange.reset(new array_type_def::subrange_type(ctxt->ir_env,
+                                                   "",
+                                                   lower_bound,
+                                                   upper_bound,
+                                                   index_type,
+                                                   location(),
+                                                   translation_unit::LANG_C));
+  if (!subrange)
+    return result;
+
+  add_decl_to_scope(subrange, tunit->get_global_scope());
+  canonicalize(subrange);
+  subranges.push_back(subrange);
+
+  /* Finally build the IR for the array type and return it.  */
+  result.reset(new array_type_def(element_type, subranges, location()));
+  return result;
+}
+
+/// Build and return a qualified type libabigail IR.
+///
+/// @param ctxt 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(read_context *ctxt,
+                           corpus_sptr corp,
+                           translation_unit_sptr tunit,
+                           ctf_dict_t *ctf_dictionary,
+                           ctf_id_t ctf_type)
+{
+  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 = lookup_type(ctxt, corp, tunit,
+                                     ctf_dictionary, ctf_utype);
+  if (!utype)
+    return result;
+
+  qualified_type_def::CV qualifiers = qualified_type_def::CV_NONE;
+  if (type_kind == CTF_K_CONST)
+    qualifiers |= qualified_type_def::CV_CONST;
+  else if (type_kind == CTF_K_VOLATILE)
+    qualifiers |= qualified_type_def::CV_VOLATILE;
+  else if (type_kind == CTF_K_RESTRICT)
+    qualifiers |= qualified_type_def::CV_RESTRICT;
+  else
+    ABG_ASSERT_NOT_REACHED;
+
+  result.reset(new qualified_type_def(utype, qualifiers, location()));
+  return result;
+}
+
+/// Build and return a pointer type libabigail IR.
+///
+/// @param ctxt 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 pointer type.
+
+static pointer_type_def_sptr
+process_ctf_pointer_type(read_context *ctxt,
+                         corpus_sptr corp,
+                         translation_unit_sptr tunit,
+                         ctf_dict_t *ctf_dictionary,
+                         ctf_id_t ctf_type)
+{
+  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 = lookup_type(ctxt, corp, tunit,
+                                           ctf_dictionary,
+                                           ctf_target_type);
+  if (!target_type)
+    return result;
+
+  result.reset(new pointer_type_def(target_type,
+                                      ctf_type_size(ctf_dictionary, ctf_type) * 8,
+                                      ctf_type_align(ctf_dictionary, ctf_type) * 8,
+                                      location()));
+  return result;
+}
+
+/// Build and return an enum type libabigail IR.
+///
+/// @param ctxt 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 enum type.
+
+static enum_type_decl_sptr
+process_ctf_enum_type(read_context *ctxt,
+                      translation_unit_sptr tunit,
+                      ctf_dict_t *ctf_dictionary,
+                      ctf_id_t ctf_type)
+{
+  enum_type_decl_sptr result;
+
+  /* Build a signed integral type for the type of the enumerators, aka
+     the underlying type.  The size of the enumerators in bytes is
+     specified in the CTF enumeration type.  */
+  size_t utype_size_in_bits = ctf_type_size(ctf_dictionary, ctf_type) * 8;
+  type_decl_sptr utype;
+
+  utype.reset(new type_decl(ctxt->ir_env,
+                              "",
+                              utype_size_in_bits,
+                              utype_size_in_bits,
+                              location()));
+  utype->set_is_anonymous(true);
+  utype->set_is_artificial(true);
+  if (!utype)
+    return result;
+  add_decl_to_scope(utype, tunit->get_global_scope());
+  canonicalize(utype);
+
+  /* Iterate over the enum entries.  */
+  enum_type_decl::enumerators enms;
+  ctf_next_t *enum_next = NULL;
+  const char *ename;
+  int evalue;
+
+  while ((ename = ctf_enum_next(ctf_dictionary, ctf_type, &enum_next, &evalue)))
+    enms.push_back(enum_type_decl::enumerator(ctxt->ir_env, ename, evalue));
+  if (ctf_errno(ctf_dictionary) != ECTF_NEXT_END)
+    {
+      fprintf(stderr, "ERROR from ctf_enum_next\n");
+      return result;
+    }
+
+  const char *enum_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
+  result.reset(new enum_type_decl(enum_name, location(),
+                                  utype, enms, enum_name));
+  return result;
+}
+
+/// Add a new type declaration to the given libabigail IR corpus CORP.
+///
+/// @param ctxt 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.
+///
+/// Note that if @ref ctf_type can't reliably be translated to the IR
+/// then it is simply ignored.
+///
+/// @return a shared pointer to the IR node for the type.
+
+static type_base_sptr
+process_ctf_type(read_context *ctxt,
+                 corpus_sptr corp,
+                 translation_unit_sptr tunit,
+                 ctf_dict_t *ctf_dictionary,
+                 ctf_id_t ctf_type)
+{
+  int type_kind = ctf_type_kind(ctf_dictionary, ctf_type);
+  type_base_sptr result;
+
+  switch (type_kind)
+    {
+    case CTF_K_INTEGER:
+    case CTF_K_FLOAT:
+      {
+        type_decl_sptr type_decl
+          = process_ctf_base_type(ctxt, corp, ctf_dictionary, ctf_type);
+
+        if (type_decl)
+          {
+            add_decl_to_scope(type_decl, tunit->get_global_scope());
+            result = is_type(type_decl);
+          }
+        break;
+      }
+    case CTF_K_TYPEDEF:
+      {
+        typedef_decl_sptr typedef_decl
+          = process_ctf_typedef(ctxt, corp, tunit, ctf_dictionary, ctf_type);
+
+        if (typedef_decl)
+          {
+            add_decl_to_scope(typedef_decl, tunit->get_global_scope());
+            result = is_type(typedef_decl);
+          }
+        break;
+      }
+    case CTF_K_POINTER:
+      {
+        pointer_type_def_sptr pointer_type
+          = process_ctf_pointer_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
+
+        if (pointer_type)
+          {
+            add_decl_to_scope(pointer_type, tunit->get_global_scope());
+            result = pointer_type;
+          }
+        break;
+      }
+    case CTF_K_CONST:
+    case CTF_K_VOLATILE:
+    case CTF_K_RESTRICT:
+      {
+        type_base_sptr qualified_type
+          = process_ctf_qualified_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
+
+        if (qualified_type)
+          {
+            decl_base_sptr qualified_type_decl = get_type_declaration(qualified_type);
+
+            add_decl_to_scope(qualified_type_decl, tunit->get_global_scope());
+            result = qualified_type;
+          }
+        break;
+      }
+    case CTF_K_ARRAY:
+      {
+        array_type_def_sptr array_type
+          = process_ctf_array_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
+
+        if (array_type)
+          {
+            decl_base_sptr array_type_decl = get_type_declaration(array_type);
+
+            add_decl_to_scope(array_type_decl, tunit->get_global_scope());
+            result = array_type;
+          }
+        break;
+      }
+    case CTF_K_ENUM:
+      {
+        enum_type_decl_sptr enum_type
+          = process_ctf_enum_type(ctxt, tunit, ctf_dictionary, ctf_type);
+
+        if (enum_type)
+          {
+            add_decl_to_scope(enum_type, tunit->get_global_scope());
+            result = enum_type;
+          }
+
+        break;
+      }
+    case CTF_K_FUNCTION:
+      {
+        function_type_sptr function_type
+          = process_ctf_function_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
+
+        if (function_type)
+          {
+            decl_base_sptr function_type_decl = get_type_declaration(function_type);
+
+            add_decl_to_scope(function_type_decl, tunit->get_global_scope());
+            result = function_type;
+          }
+        break;
+      }
+    case CTF_K_STRUCT:
+      {
+        class_decl_sptr struct_decl
+          = process_ctf_struct_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
+
+        if (struct_decl)
+          {
+            add_decl_to_scope(struct_decl, tunit->get_global_scope());
+            result = is_type(struct_decl);
+          }
+        break;
+      }
+    case CTF_K_UNION:
+      {
+        union_decl_sptr union_decl
+          = process_ctf_union_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
+
+        if (union_decl)
+          {
+            add_decl_to_scope(union_decl, tunit->get_global_scope());
+            result = is_type(union_decl);
+          }
+        break;
+      }
+    case CTF_K_UNKNOWN:
+      /* Unknown types are simply ignored.  */
+    default:
+      break;
+    }
+
+  if (result)
+    ctxt->add_type(ctf_type, result);
+  else
+    fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
+
+  return result;
+}
+
+/// Given a CTF type id, lookup the corresponding libabigail IR type.
+/// If the IR type hasn't been generated yet, generate it.
+///
+/// @param ctxt 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 looked type.
+///
+/// Note that if @ref ctf_type can't reliably be translated to the IR
+/// then a NULL shared pointer is returned.
+///
+/// @return a shared pointer to the IR node for the type.
+
+static type_base_sptr
+lookup_type(read_context *ctxt, corpus_sptr corp,
+            translation_unit_sptr tunit, ctf_dict_t *ctf_dictionary,
+            ctf_id_t ctf_type)
+{
+  type_base_sptr result = ctxt->lookup_type(ctf_type);
+
+  if (!result)
+    result = process_ctf_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
+  return result;
+}
+
+/// Process a CTF archive and create libabigail IR for the types,
+/// variables and function declarations found in the archive.  The IR
+/// is added to the given corpus.
+///
+/// @param ctxt the read context containing the CTF archive to
+/// process.
+/// @param corp the IR corpus to which add the new contents.
+
+static void
+process_ctf_archive(read_context *ctxt, corpus_sptr corp)
+{
+  /* We only have a translation unit.  */
+  translation_unit_sptr ir_translation_unit =
+    std::make_shared<translation_unit>(ctxt->ir_env, "", 64);
+  ir_translation_unit->set_language(translation_unit::LANG_C);
+  corp->add(ir_translation_unit);
+
+  /* Iterate over the CTF dictionaries in the archive.  */
+  int ctf_err;
+  ctf_dict_t *ctf_dict;
+  ctf_next_t *dict_next = NULL;
+  const char *archive_name;
+
+  while ((ctf_dict = ctf_archive_next(ctxt->ctfa, &dict_next, &archive_name,
+                                      0 /* skip_parent */, &ctf_err)) != NULL)
+    {
+      /* Iterate over the CTF types stored in this archive.  */
+      ctf_id_t ctf_type;
+      int type_flag;
+      ctf_next_t *type_next = NULL;
+
+      while ((ctf_type = ctf_type_next(ctf_dict, &type_next, &type_flag,
+                                       1 /* want_hidden */)) != CTF_ERR)
+        {
+          process_ctf_type(ctxt, corp, ir_translation_unit,
+                            ctf_dict, ctf_type);
+        }
+      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
+        fprintf(stderr, "ERROR from ctf_type_next\n");
+
+      /* Canonicalize all the types generated above.  This must be
+         done "a posteriori" because the processing of types may
+         require other related types to not be already
+         canonicalized.  */
+      ctxt->canonicalize_all_types();
+
+      /* Iterate over the CTF variables stored in this archive.  */
+      ctf_id_t ctf_var_type;
+      ctf_next_t *var_next = NULL;
+      const char *var_name;
+
+      while ((ctf_var_type = ctf_variable_next(ctf_dict, &var_next, &var_name))
+             != CTF_ERR)
+        {
+          type_base_sptr var_type = lookup_type(ctxt, corp, ir_translation_unit,
+                                                ctf_dict, ctf_var_type);
+          if (!var_type)
+            /* Ignore variable if its type can't be sorted out.  */
+            continue;
+
+          var_decl_sptr var_declaration;
+          var_declaration.reset(new var_decl(var_name,
+                                             var_type,
+                                             location(),
+                                             var_name));
+
+          add_decl_to_scope(var_declaration,
+                             ir_translation_unit->get_global_scope());
+        }
+      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
+        fprintf(stderr, "ERROR from ctf_variable_next\n");
+
+      /* Iterate over the CTF functions stored in this archive.  */
+      ctf_next_t *func_next = NULL;
+      const char *func_name = NULL;
+      ctf_id_t ctf_sym;
+
+      while ((ctf_sym = ctf_symbol_next(ctf_dict, &func_next, &func_name,
+                                        1 /* functions symbols only */) != CTF_ERR))
+      {
+        ctf_id_t ctf_func_type = ctf_lookup_by_name(ctf_dict, func_name);
+        type_base_sptr func_type = lookup_type(ctxt, corp, ir_translation_unit,
+                                               ctf_dict, ctf_func_type);
+        if (!func_type)
+          /* Ignore function if its type can't be sorted out.  */
+          continue;
+
+        elf_symbols func_elf_symbols = ctxt->symtab->lookup_symbol(func_name);
+        if (func_elf_symbols.size() == 0
+            || func_elf_symbols[0]->get_binding() == elf_symbol::LOCAL_BINDING)
+          /* Ignore local functions.  */
+          continue;
+
+        function_decl_sptr func_declaration;
+        func_declaration.reset(new function_decl(func_name,
+                                                 func_type,
+                                                 0 /* is_inline */,
+                                                 location()));
+
+        add_decl_to_scope(func_declaration,
+                           ir_translation_unit->get_global_scope());
+      }
+      if (ctf_errno(ctf_dict) != ECTF_NEXT_END)
+        fprintf(stderr, "ERROR from ctf_symbol_next\n");
+    }
+  if (ctf_err != ECTF_NEXT_END)
+    fprintf(stderr, "ERROR from ctf_archive_next\n");
+
+}
+
+/// 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)
+{
+  /* libelf requires to negotiate/set the version of ELF.  */
+  if (elf_version(EV_CURRENT) == EV_NONE)
+    return 0;
+
+  /* Open an ELF handler.  */
+  int elf_fd = open(ctxt->filename.c_str(), O_RDONLY);
+  if (elf_fd == -1)
+    return 0;
+
+  Elf *elf_handler = elf_begin(elf_fd, ELF_C_READ, NULL);
+  if (elf_handler == NULL)
+    {
+      fprintf(stderr, "cannot open %s: %s\n",
+               ctxt->filename.c_str(), elf_errmsg(elf_errno()));
+      close(elf_fd);
+      return 0;
+    }
+
+  /* Set the ELF architecture.  */
+  GElf_Ehdr eh_mem;
+  GElf_Ehdr *ehdr = gelf_getehdr(elf_handler, &eh_mem);
+  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(elf_handler, ctxt->ir_env,
+                                0 /* No suppressions.  */);
+  corp->set_symtab(ctxt->symtab);
+
+  /* Finish the ELF handler and close the associated file.  */
+  elf_end(elf_handler);
+  close(elf_fd);
+
+  return 1;
+}
+
+/// Create and return a new read context to process CTF information
+/// from a given ELF file.
+///
+/// @param elf_path the patch of some ELF file.
+/// @param env a libabigail IR environment.
+
+read_context *
+create_read_context(std::string elf_path, ir::environment *env)
+{
+  return new read_context(elf_path, env);
+}
+
+/// Read the CTF information from some source described by a given
+/// read context and process it to create a libabigail IR corpus.
+/// Store the corpus in the same read context.
+///
+/// @param ctxt the read context to use.
+/// @return a shared pointer to the read corpus.
+
+corpus_sptr
+read_corpus(read_context *ctxt)
+{
+  corpus_sptr corp
+    = std::make_shared<corpus>(ctxt->ir_env, ctxt->filename);
+
+  /* Set some properties of the corpus first.  */
+  corp->set_origin(corpus::CTF_ORIGIN);
+  if (!slurp_elf_info(ctxt, corp))
+    return corp;
+
+  /* Get out now if no CTF debug info is found.  */
+  if (ctxt->ctfa == NULL)
+    return corp;
+
+  /* Process the CTF archive in the read context, if any.  Information
+     about the types, variables, functions, etc contained in the
+     archive are added to the given corpus.  */
+  process_ctf_archive(ctxt, corp);
+  return corp;
+}
+
+} // End of namespace ctf_reader
+} // End of namespace abigail
diff --git a/tools/abidiff.cc b/tools/abidiff.cc
index 21f7ff61..56f57448 100644
--- a/tools/abidiff.cc
+++ b/tools/abidiff.cc
@@ -19,6 +19,9 @@
 #include "abg-tools-utils.h"
 #include "abg-reader.h"
 #include "abg-dwarf-reader.h"
+#ifdef WITH_CTF
+#include "abg-ctf-reader.h"
+#endif
 
 using std::vector;
 using std::string;
@@ -104,6 +107,9 @@ struct options
 #ifdef WITH_DEBUG_SELF_COMPARISON
   bool			do_debug;
 #endif
+#ifdef WITH_CTF
+  bool			use_ctf;
+#endif
   vector<char*> di_root_paths1;
   vector<char*> di_root_paths2;
   vector<char**> prepared_di_root_paths1;
@@ -145,6 +151,10 @@ struct options
       dump_diff_tree(),
       show_stats(),
       do_log()
+#ifdef WITH_CTF
+    ,
+      use_ctf()
+#endif
 #ifdef WITH_DEBUG_SELF_COMPARISON
     ,
     do_debug()
@@ -233,6 +243,7 @@ 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_DEBUG_SELF_COMPARISON
     << " --debug debug the process of comparing an ABI corpus against itself"
 #endif
@@ -579,6 +590,10 @@ parse_command_line(int argc, char* argv[], options& opts)
 	opts.show_stats = true;
       else if (!strcmp(argv[i], "--verbose"))
 	opts.do_log = true;
+#ifdef WITH_CTF
+      else if (!strcmp(argv[i], "--ctf"))
+        opts.use_ctf = true;
+#endif
 #ifdef WITH_DEBUG_SELF_COMPARISON
       else if (!strcmp(argv[i], "--debug"))
 	opts.do_debug = true;
@@ -1150,23 +1165,37 @@ main(int argc, char* argv[])
 	case abigail::tools_utils::FILE_TYPE_ELF: // fall through
 	case abigail::tools_utils::FILE_TYPE_AR:
 	  {
-	    abigail::dwarf_reader::read_context_sptr ctxt =
-	      abigail::dwarf_reader::create_read_context
-	      (opts.file1, opts.prepared_di_root_paths1,
-	       env.get(), /*read_all_types=*/opts.show_all_types,
-	       opts.linux_kernel_mode);
-	    assert(ctxt);
-
-	    abigail::dwarf_reader::set_show_stats(*ctxt, opts.show_stats);
-	    set_suppressions(*ctxt, opts);
-	    abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
-	    c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
-	    if (!c1
-		|| (opts.fail_no_debug_info
-		    && (c1_status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
-		    && (c1_status & STATUS_DEBUG_INFO_NOT_FOUND)))
-	      return handle_error(c1_status, ctxt.get(),
-				  argv[0], opts);
+#ifdef WITH_CTF
+            if (opts.use_ctf)
+              {
+                abigail::ctf_reader::read_context *ctxt
+                  = abigail::ctf_reader::create_read_context (opts.file1,
+                                                              env.get());
+
+                assert (ctxt);
+                c1 = abigail::ctf_reader::read_corpus (ctxt);
+              }
+            else
+#endif
+              {
+                abigail::dwarf_reader::read_context_sptr ctxt =
+                  abigail::dwarf_reader::create_read_context
+                  (opts.file1, opts.prepared_di_root_paths1,
+                   env.get(), /*read_all_types=*/opts.show_all_types,
+                   opts.linux_kernel_mode);
+                assert(ctxt);
+
+                abigail::dwarf_reader::set_show_stats(*ctxt, opts.show_stats);
+                set_suppressions(*ctxt, opts);
+                abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
+                c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
+                if (!c1
+                    || (opts.fail_no_debug_info
+                        && (c1_status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
+                        && (c1_status & STATUS_DEBUG_INFO_NOT_FOUND)))
+                  return handle_error(c1_status, ctxt.get(),
+                                      argv[0], opts);
+              }
 	  }
 	  break;
 	case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
@@ -1219,23 +1248,36 @@ main(int argc, char* argv[])
 	case abigail::tools_utils::FILE_TYPE_ELF: // Fall through
 	case abigail::tools_utils::FILE_TYPE_AR:
 	  {
-	    abigail::dwarf_reader::read_context_sptr ctxt =
-	      abigail::dwarf_reader::create_read_context
-	      (opts.file2, opts.prepared_di_root_paths2,
-	       env.get(), /*read_all_types=*/opts.show_all_types,
-	       opts.linux_kernel_mode);
-	    assert(ctxt);
-	    abigail::dwarf_reader::set_show_stats(*ctxt, opts.show_stats);
-	    abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
-	    set_suppressions(*ctxt, opts);
-
-	    c2 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c2_status);
-	    if (!c2
-		|| (opts.fail_no_debug_info
-		    && (c2_status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
-		    && (c2_status & STATUS_DEBUG_INFO_NOT_FOUND)))
-	      return handle_error(c2_status, ctxt.get(), argv[0], opts);
-
+#ifdef WITH_CTF
+            if (opts.use_ctf)
+              {
+                abigail::ctf_reader::read_context *ctxt
+                  = abigail::ctf_reader::create_read_context (opts.file2,
+                                                              env.get());
+
+                assert (ctxt);
+                c2 = abigail::ctf_reader::read_corpus (ctxt);
+              }
+            else
+#endif
+              {
+                abigail::dwarf_reader::read_context_sptr ctxt =
+                  abigail::dwarf_reader::create_read_context
+                  (opts.file2, opts.prepared_di_root_paths2,
+                   env.get(), /*read_all_types=*/opts.show_all_types,
+                   opts.linux_kernel_mode);
+                assert(ctxt);
+                abigail::dwarf_reader::set_show_stats(*ctxt, opts.show_stats);
+                abigail::dwarf_reader::set_do_log(*ctxt, opts.do_log);
+                set_suppressions(*ctxt, opts);
+
+                c2 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c2_status);
+                if (!c2
+                    || (opts.fail_no_debug_info
+                        && (c2_status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
+                        && (c2_status & STATUS_DEBUG_INFO_NOT_FOUND)))
+                  return handle_error(c2_status, ctxt.get(), argv[0], opts);
+              }
 	  }
 	  break;
 	case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
diff --git a/tools/abilint.cc b/tools/abilint.cc
index 856f935d..a0ded0a9 100644
--- a/tools/abilint.cc
+++ b/tools/abilint.cc
@@ -13,6 +13,7 @@
 /// runs a diff on the two files and expects the result of the diff to
 /// be empty.
 
+#include "config.h"
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
@@ -27,6 +28,9 @@
 #include "abg-corpus.h"
 #include "abg-reader.h"
 #include "abg-dwarf-reader.h"
+#ifdef WITH_CTF
+#include "abg-ctf-reader.h"
+#endif
 #include "abg-writer.h"
 #include "abg-suppression.h"
 
@@ -67,6 +71,9 @@ struct options
   bool				read_tu;
   bool				diff;
   bool				noout;
+#ifdef WITH_CTF
+  bool				use_ctf;
+#endif
   std::shared_ptr<char>	di_root_path;
   vector<string>		suppression_paths;
   string			headers_dir;
@@ -78,6 +85,10 @@ struct options
       read_tu(false),
       diff(false),
       noout(false)
+#ifdef WITH_CTF
+    ,
+      use_ctf(false)
+#endif
   {}
 };//end struct options;
 
@@ -99,7 +110,11 @@ display_usage(const string& prog_name, ostream& out)
     "the input and the memory model saved back to disk\n"
     << "  --noout  do not display anything on stdout\n"
     << "  --stdin|--  read abi-file content from stdin\n"
-    << "  --tu  expect a single translation unit file\n";
+    << "  --tu  expect a single translation unit file\n"
+#ifdef WITH_CTF
+    << "  --ctf use CTF instead of DWARF in ELF files\n"
+#endif
+    ;
 }
 
 bool
@@ -173,6 +188,10 @@ parse_command_line(int argc, char* argv[], options& opts)
 	  opts.read_from_stdin = true;
 	else if (!strcmp(argv[i], "--tu"))
 	  opts.read_tu = true;
+#ifdef WITH_CTF
+        else if (!strcmp(argv[i], "--ctf"))
+          opts.use_ctf = true;
+#endif
 	else if (!strcmp(argv[i], "--diff"))
 	  opts.diff = true;
 	else if (!strcmp(argv[i], "--noout"))
@@ -338,13 +357,28 @@ main(int argc, char* argv[])
 	    di_root_path = opts.di_root_path.get();
 	    vector<char**> di_roots;
 	    di_roots.push_back(&di_root_path);
-	    abigail::dwarf_reader::read_context_sptr ctxt =
-	      abigail::dwarf_reader::create_read_context(opts.file_path,
-							 di_roots, env.get(),
-							 /*load_all_types=*/false);
-	    assert(ctxt);
-	    set_suppressions(*ctxt, opts);
-	    corp = read_corpus_from_elf(*ctxt, s);
+
+#ifdef WITH_CTF
+            if (opts.use_ctf)
+              {
+                abigail::ctf_reader::read_context *ctxt
+                  = abigail::ctf_reader::create_read_context (opts.file_path,
+                                                              env.get());
+
+                assert (ctxt);
+                corp = abigail::ctf_reader::read_corpus (ctxt);
+              }
+            else
+#endif
+              {
+                abigail::dwarf_reader::read_context_sptr ctxt =
+                  abigail::dwarf_reader::create_read_context(opts.file_path,
+                                                             di_roots, env.get(),
+                                                             /*load_all_types=*/false);
+                assert(ctxt);
+                set_suppressions(*ctxt, opts);
+                corp = read_corpus_from_elf(*ctxt, s);
+              }
 	  }
 	  break;
 	case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
