diff --git a/include/Makefile.am b/include/Makefile.am
index b3b9148f..6b7f1e49 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -4,8 +4,10 @@ abg-sptr-utils.h	\
 abg-interned-str.h	\
 abg-ir.h		\
 abg-corpus.h		\
+abg-fe-iface.h		\
+abg-elf-based-reader.h  \
+abg-elf-reader.h	\
 abg-reader.h		\
-abg-elf-reader-common.h \
 abg-dwarf-reader.h	\
 abg-writer.h		\
 abg-comparison.h	\
diff --git a/include/abg-corpus.h b/include/abg-corpus.h
index 27de8c2f..20ec4f41 100644
--- a/include/abg-corpus.h
+++ b/include/abg-corpus.h
@@ -60,21 +60,15 @@ public:
   struct priv;
   std::unique_ptr<priv> priv_;
 
-  corpus(ir::environment*, const string& path= "");
+  corpus(const ir::environment&, const string& path= "");
 
   virtual ~corpus();
 
-  const environment*
+  const environment&
   get_environment() const;
 
-  environment*
-  get_environment();
-
-  void
-  set_environment(environment*);
-
   void
-  add(const translation_unit_sptr);
+  add(const translation_unit_sptr&);
 
   const translation_units&
   get_translation_units() const;
@@ -332,10 +326,10 @@ public:
   exported_variables();
 
   void
-  maybe_add_fn_to_exported_fns(function_decl*);
+  maybe_add_fn_to_exported_fns(const function_decl*);
 
   void
-  maybe_add_var_to_exported_vars(var_decl*);
+  maybe_add_var_to_exported_vars(const var_decl*);
 }; //corpus::exported_decls_builder
 
 /// Abstraction of a group of corpora.
@@ -355,7 +349,7 @@ class corpus_group : public corpus
 public:
   typedef vector<corpus_sptr> corpora_type;
 
-  corpus_group(ir::environment*, const string&);
+  corpus_group(const ir::environment&, const string&);
 
   virtual ~corpus_group();
 
diff --git a/include/abg-ctf-reader.h b/include/abg-ctf-reader.h
index 0f49b5eb..ea19683e 100644
--- a/include/abg-ctf-reader.h
+++ b/include/abg-ctf-reader.h
@@ -17,7 +17,7 @@
 #include <ostream>
 #include "abg-corpus.h"
 #include "abg-suppression.h"
-#include "abg-elf-reader-common.h"
+#include "abg-elf-based-reader.h"
 
 #include "ctf-api.h"
 
@@ -26,32 +26,15 @@ namespace abigail
 namespace ctf_reader
 {
 
-class read_context;
-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);
-
-corpus_sptr
-read_corpus(const read_context_sptr &ctxt, elf_reader::status &status);
-
-corpus_sptr
-read_and_add_corpus_to_group_from_elf(read_context*, corpus_group&, elf_reader::status&);
-
-void
-set_read_context_corpus_group(read_context& ctxt, corpus_group_sptr& group);
+elf_based_reader_sptr
+create_ctf_reader(const std::string& elf_path,
+		  const vector<char**>& debug_info_root_paths,
+		  environment& env);
 
 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);
+reset_reader(elf_based_reader&		ctxt,
+	     const std::string&	elf_path,
+	     const vector<char**>&	debug_info_root_path);
 } // end namespace ctf_reader
 } // end namespace abigail
 
diff --git a/include/abg-dwarf-reader.h b/include/abg-dwarf-reader.h
index 5766f906..f325da32 100644
--- a/include/abg-dwarf-reader.h
+++ b/include/abg-dwarf-reader.h
@@ -18,7 +18,7 @@
 #include <elfutils/libdwfl.h>
 #include "abg-corpus.h"
 #include "abg-suppression.h"
-#include "abg-elf-reader-common.h"
+#include "abg-elf-based-reader.h"
 
 namespace abigail
 {
@@ -29,131 +29,39 @@ namespace dwarf_reader
 
 using namespace abigail::ir;
 
-/// The kind of ELF file we are looking at.
-enum elf_type
-{
-  /// A normal executable binary
-  ELF_TYPE_EXEC,
-  /// A Position Independant Executable binary
-  ELF_TYPE_PI_EXEC,
-  /// A dynamic shared object, a.k.a shared library binrary.
-  ELF_TYPE_DSO,
-  /// A relocatalbe binary.
-  ELF_TYPE_RELOCATABLE,
-  /// An unknown kind of binary.
-  ELF_TYPE_UNKNOWN
-};
-
-class read_context;
-
-/// A convenience typedef for a smart pointer to a
-/// dwarf_reader::read_context.
-typedef shared_ptr<read_context> read_context_sptr;
-
-read_context_sptr
-create_read_context(const std::string&	elf_path,
+elf_based_reader_sptr
+create_dwarf_reader(const std::string&	elf_path,
 		    const vector<char**>& debug_info_root_paths,
-		    ir::environment*	environment,
+		    environment&	environment,
 		    bool		read_all_types = false,
 		    bool		linux_kernel_mode = false);
 
-const string&
-read_context_get_path(const read_context&);
-
 void
-reset_read_context(read_context_sptr &ctxt,
-		   const std::string&	elf_path,
-		   const vector<char**>& debug_info_root_paths,
-		   ir::environment*	environment,
-		   bool		read_all_types = false,
-		   bool		linux_kernel_mode = false);
-
-void
-add_read_context_suppressions(read_context& ctxt,
-			      const suppr::suppressions_type& supprs);
-
-void
-set_read_context_corpus_group(read_context& ctxt, corpus_group_sptr& group);
+reset_dwarf_reader(elf_based_reader&		rdr,
+		   const std::string&		elf_path,
+		   const vector<char**>&	debug_info_root_paths,
+		   bool			read_all_types = false,
+		   bool			linux_kernel_mode = false);
 
 corpus_sptr
-read_corpus_from_elf(read_context& ctxt, elf_reader::status& stat);
-
-corpus_sptr
-read_corpus_from_elf(const std::string& elf_path,
-		     const vector<char**>& debug_info_root_paths,
-		     ir::environment*	environment,
-		     bool		load_all_types,
-		     elf_reader::status&);
-
-corpus_sptr
-read_and_add_corpus_to_group_from_elf(read_context&, corpus_group&, elf_reader::status&);
+read_corpus_from_elf(const std::string&	elf_path,
+		     const vector<char**>&	debug_info_root_paths,
+		     environment&		environment,
+		     bool			load_all_types,
+		     fe_iface::status&		status);
 
 bool
-lookup_symbol_from_elf(const environment*		env,
+lookup_symbol_from_elf(environment&			env,
 		       const string&			elf_path,
 		       const string&			symbol_name,
 		       bool				demangle,
 		       vector<elf_symbol_sptr>&	symbols);
 
 bool
-lookup_public_function_symbol_from_elf(const environment*		env,
+lookup_public_function_symbol_from_elf(environment&			env,
 				       const string&			path,
 				       const string&			symname,
 				       vector<elf_symbol_sptr>&	func_syms);
-
-bool
-refers_to_alt_debug_info(const read_context&	ctxt,
-			 string&		alt_di_path);
-
-elf_reader::status
-has_alt_debug_info(read_context&	ctxt,
-		   bool&		has_alt_di,
-		   string&		alt_debug_info_path);
-
-elf_reader::status
-has_alt_debug_info(const string&	elf_path,
-		   char**		debug_info_root_path,
-		   bool&		has_alt_di,
-		   string&		alt_debug_info_path);
-
-bool
-get_soname_of_elf_file(const string& path, string& soname);
-
-bool
-get_type_of_elf_file(const string& path, elf_type& type);
-
-
-void
-set_debug_info_root_path(read_context& ctxt,
-			 char** path);
-
-char**
-get_debug_info_root_path(read_context& ctxt,
-			 char**& path);
-
-bool
-get_show_stats(read_context& ctxt);
-
-void
-set_show_stats(read_context& ctxt,
-	       bool f);
-
-void
-set_drop_undefined_syms(read_context& ctxt,
-			bool f);
-
-void
-set_do_log(read_context& ctxt, bool f);
-
-void
-set_environment(read_context& ctxt,
-		ir::environment*);
-
-const environment_sptr&
-get_environment(const read_context& ctxt);
-
-environment_sptr&
-get_environment(read_context& ctxt);
 }// end namespace dwarf_reader
 
 }// end namespace abigail
diff --git a/include/abg-elf-based-reader.h b/include/abg-elf-based-reader.h
new file mode 100644
index 00000000..8916822f
--- /dev/null
+++ b/include/abg-elf-based-reader.h
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// -*- Mode: C++ -*-
+//
+// Copyright (C) 2022 Red Hat, Inc.
+//
+// Author: Dodji Seketeli
+
+/// @file
+///
+/// This file contains the declarations for an elf-based.  DWARF and
+/// CTF readers can inherit this one.
+
+
+#ifndef __ABG_ELF_BASED_READER_H__
+#define __ABG_ELF_BASED_READER_H__
+
+#include <memory>
+#include <string>
+
+#include "abg-elf-reader.h"
+#include "abg-corpus.h"
+
+namespace abigail
+{
+
+/// The common interface of readers based on ELF.
+///
+/// These are for readers like DWARF and CTF readers that read debug
+/// information describing binaries in the ELF format.
+///
+/// This interface extends the elf_reader::reader interface and thus
+/// also provides facilities for reading ELF binaries.
+class elf_based_reader : public elf_reader::reader
+{
+  struct priv;
+  priv* priv_;
+
+  elf_based_reader() = delete;
+
+protected:
+
+  /// Readers that implement this interface must provide a factory
+  /// method to create a reader instance as this constructor is
+  /// protected.
+  elf_based_reader(const std::string& elf_path,
+		   const vector<char**>& debug_info_root_paths,
+		   environment& env);
+public:
+
+  ~elf_based_reader();
+
+  virtual void
+  reset(const std::string& elf_path,
+	const vector<char**>& debug_info_root_paths);
+
+  virtual ir::corpus_sptr
+  read_and_add_corpus_to_group(ir::corpus_group& group,
+			       fe_iface::status& status);
+};//end class elf_based_reader
+
+typedef std::shared_ptr<elf_based_reader> elf_based_reader_sptr;
+}// namespace
+#endif
diff --git a/include/abg-elf-reader-common.h b/include/abg-elf-reader-common.h
deleted file mode 100644
index 3f4d49b0..00000000
--- a/include/abg-elf-reader-common.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-// -*- Mode: C++ -*-
-//
-// Copyright (C) 2021-2022 Oracle, Inc.
-//
-// Author: Jose E. Marchesi
-
-/// @file
-///
-/// This file contains declarations implementing the different status
-/// in which a corpus read from an ELF file can result.  It is used by
-/// the readers based on ELF files, such as DWARF and CTF.
-///
-/// More generally, this file contains declarations related to
-/// facilities shared by the various readers that handle the ELF
-/// format, e.g, the DWARF and CTF realder.
-
-#ifndef __ABG_ELF_READER_COMMON_H__
-#define __ABG_ELF_READER_COMMON_H__
-
-#include <string>
-
-namespace abigail
-{
-
-/// The namespace for an ELF based reader.
-namespace elf_reader
-{
-
-/// The status of the @ref read_corpus_from_elf() call.
-enum status
-{
-  /// The status is in an unknown state
-  STATUS_UNKNOWN = 0,
-
-  /// This status is for when the call went OK.
-  STATUS_OK = 1,
-
-  /// This status is for when the debug info could not be read.
-  STATUS_DEBUG_INFO_NOT_FOUND = 1 << 1,
-
-  /// This status is for when the alternate debug info could not be
-  /// found.
-  STATUS_ALT_DEBUG_INFO_NOT_FOUND = 1 << 2,
-
-  /// This status is for when the symbols of the ELF binaries could
-  /// not be read.
-  STATUS_NO_SYMBOLS_FOUND = 1 << 3,
-};
-
-std::string
-status_to_diagnostic_string(status s);
-
-status
-operator|(status, status);
-
-status
-operator&(status, status);
-
-status&
-operator|=(status&, status);
-
-status&
-operator&=(status&, status);
-
-}// end namespace elf_reader
-
-}// end namespace abigail
-
-#endif //__ABG_ELF_READER_COMMON_H__
diff --git a/include/abg-elf-reader.h b/include/abg-elf-reader.h
new file mode 100644
index 00000000..c6cecf0f
--- /dev/null
+++ b/include/abg-elf-reader.h
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// -*- Mode: C++ -*-
+//
+// Copyright (C) 2022 Red Hat, Inc.
+//
+// Author: Dodji Seketeli
+
+/// @file
+///
+/// This file contains the declarations for the @ref fe_iface a.k.a
+/// "Front End Interface".
+
+#ifndef __ABG_ELF_READER_H__
+#define __ABG_ELF_READER_H__
+
+#include <memory>
+#include <string>
+
+#include <elfutils/libdwfl.h>
+
+#include "abg-fe-iface.h"
+#include "abg-ir.h"
+#include "abg-suppression.h"
+
+namespace abigail
+{
+
+/// The namespace for the ELF Reader.
+namespace elf_reader
+{
+
+/// The kind of ELF file we are looking at.
+enum elf_type : unsigned
+{
+  /// A normal executable binary
+  ELF_TYPE_EXEC,
+  /// A Position Independant Executable binary
+  ELF_TYPE_PI_EXEC,
+  /// A dynamic shared object, a.k.a shared library binary.
+  ELF_TYPE_DSO,
+  /// A relocatalbe binary.
+  ELF_TYPE_RELOCATABLE,
+  /// An unknown kind of binary.
+  ELF_TYPE_UNKNOWN
+};
+
+/// This is the interface an ELF reader.
+///
+/// It knows how to open an ELF file, read its content and expose an
+/// interface for its symbol table and other properties.
+///
+/// Note that the ABI corpus returned by the elf_reader::read_corpus()
+/// member function doesn't contain any type representation.  It only
+/// contains the representations of the the ELF symbols found in the
+/// ELF file.
+///
+/// To construct the type representations for the functions and global
+/// variables present in the ELF file, please use the implementations
+/// of the @ref elf_based_reader interface.  Those know how to read
+/// the debug information from the ELF file to build type
+/// representation in the @ref abigail::ir::corpus instance.
+class reader : public fe_iface
+{
+  struct priv;
+  priv *priv_;
+
+ public:
+
+  reader(const std::string&	elf_path,
+	 const vector<char**>&	debug_info_roots,
+	 environment&		env);
+
+  ~reader();
+
+  void
+  reset(const std::string&	elf_path,
+	 const vector<char**>&	debug_info_roots);
+
+  const vector<char**>&
+  debug_info_root_paths() const;
+
+  const Dwfl_Callbacks&
+  dwfl_offline_callbacks() const;
+
+  Dwfl_Callbacks&
+  dwfl_offline_callbacks();
+
+  Elf*
+  elf_handle() const;
+
+  const Dwarf*
+  dwarf_debug_info() const;
+
+  const Dwarf*
+  alternate_dwarf_debug_info() const;
+
+  const string&
+  alternate_dwarf_debug_info_path() const;
+
+  bool
+  refers_to_alt_debug_info(string& alt_di_path) const;
+
+  const Elf_Scn*
+  find_symbol_table_section() const;
+
+  void
+  reset_symbol_table_section();
+
+  const Elf_Scn*
+  find_ctf_section() const;
+
+  const Elf_Scn*
+  find_alternate_ctf_section() const;
+
+  const vector<string>&
+  dt_needed()const;
+
+  const string&
+  elf_architecture() const;
+
+  symtab_reader::symtab_sptr&
+  symtab() const;
+
+  elf_symbol_sptr
+  function_symbol_is_exported(GElf_Addr symbol_address) const;
+
+  elf_symbol_sptr
+  variable_symbol_is_exported(GElf_Addr symbol_address) const;
+
+  void
+  load_dt_soname_and_needed();
+
+  void
+  load_elf_architecture();
+
+  void
+  load_elf_properties();
+
+  virtual ir::corpus_sptr
+  read_corpus(status& status);
+};//end class reader.
+
+/// A convenience typedef for a smart pointer to a
+/// elf_reader::reader.
+typedef shared_ptr<elf_reader::reader> reader_sptr;
+
+bool
+get_soname_of_elf_file(const string& path, string &soname);
+
+bool
+get_type_of_elf_file(const string& path, elf_type& type);
+} // end namespace elf_reader.
+} // end namespace abigail
+
+#endif // __ABG_ELF_READER_H__
diff --git a/include/abg-fe-iface.h b/include/abg-fe-iface.h
new file mode 100644
index 00000000..5e6cf26f
--- /dev/null
+++ b/include/abg-fe-iface.h
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// -*- Mode: C++ -*-
+//
+// Copyright (C) 2022 Red Hat, Inc.
+//
+// Author: Dodji Seketeli
+
+/// @file
+///
+/// This file contains the declarations for the @ref fe_iface a.k.a
+/// "Front End Interface".
+
+#ifndef __ABG_FE_IFACE_H__
+#define __ABG_FE_IFACE_H__
+
+#include "abg-ir.h"
+#include "abg-suppression.h"
+
+namespace abigail
+{
+
+/// The base class of all libabigail front-ends: The Front End Interface.
+///
+/// A front end reads a given type of binary format and constructs a
+/// libagbigail internal representation from it.
+///
+/// The middle-end then manipulates that IR.
+class fe_iface
+{
+protected:
+  struct priv;
+  priv* priv_;
+
+ public:
+
+  /// The status of the @ref fe_iface::read_corpus call.
+  enum status
+  {
+    /// The status is in an unknown state
+    STATUS_UNKNOWN = 0,
+
+    /// This status is for when the call went OK.
+    STATUS_OK = 1,
+
+    /// This status is for when the debug info could not be read.
+    STATUS_DEBUG_INFO_NOT_FOUND = 1 << 1,
+
+    /// This status is for when the alternate debug info could not be
+    /// found.
+    STATUS_ALT_DEBUG_INFO_NOT_FOUND = 1 << 2,
+
+    /// This status is for when the symbols of the ELF binaries could
+    /// not be read.
+    STATUS_NO_SYMBOLS_FOUND = 1 << 3,
+  };
+
+  /// The generic options that control the behaviour of all Front-End
+  /// interfaces.
+  struct options_type
+  {
+    environment&	env;
+    bool		load_in_linux_kernel_mode	= false;
+    bool		load_all_types			= false;
+    bool		drop_undefined_syms		= false;
+    bool		show_stats			= false;
+    bool		do_log				= false;;
+    options_type(environment&);
+
+  };// font_end_iface::options_type
+
+  fe_iface(const std::string& corpus_path, environment& e);
+
+  ~fe_iface();
+
+  void
+  reset(const std::string& corpus_path, environment& e);
+
+  const options_type&
+  options() const;
+
+  options_type&
+  options();
+
+  const std::string&
+  corpus_path() const;
+
+  void
+  corpus_path(const std::string&);
+
+  const string&
+  dt_soname() const;
+
+  void
+  dt_soname(const string&);
+
+  bool
+  load_in_linux_kernel_mode() const;
+
+  suppr::suppressions_type&
+  suppressions();
+
+  const suppr::suppressions_type&
+  suppressions() const;
+
+  void
+  suppressions(suppr::suppressions_type&);
+
+  void
+  add_suppressions(const suppr::suppressions_type&);
+
+  corpus_sptr
+  corpus();
+
+  const corpus_sptr
+  corpus() const;
+
+  corpus_group_sptr&
+  corpus_group();
+
+  const corpus_group_sptr&
+  corpus_group() const;
+
+  void
+  corpus_group(const ir::corpus_group_sptr& cg);
+
+  bool
+  has_corpus_group() const;
+
+  corpus_sptr
+  main_corpus_from_current_group();
+
+  bool
+  current_corpus_is_main_corpus_from_current_group();
+
+  corpus_sptr
+  should_reuse_type_from_corpus_group();
+
+  void
+  maybe_add_fn_to_exported_decls(const function_decl* fn);
+
+  void
+  maybe_add_var_to_exported_decls(const var_decl* var);
+
+  virtual ir::corpus_sptr
+  read_corpus(status& status) = 0;
+}; //end class fe_iface
+
+typedef shared_ptr<fe_iface> fe_iface_sptr;
+
+std::string
+status_to_diagnostic_string(fe_iface::status s);
+
+fe_iface::status
+operator|(fe_iface::status, fe_iface::status);
+
+fe_iface::status
+operator&(fe_iface::status, fe_iface::status);
+
+fe_iface::status&
+operator|=(fe_iface::status&, fe_iface::status);
+
+fe_iface::status&
+operator&=(fe_iface::status&, fe_iface::status);
+
+}// end namespace abigail
+#endif // __ABG_FE_IFAC_H__
diff --git a/include/abg-fwd.h b/include/abg-fwd.h
index 1dbe99bb..33087b90 100644
--- a/include/abg-fwd.h
+++ b/include/abg-fwd.h
@@ -1384,7 +1384,7 @@ string
 demangle_cplus_mangled_name(const string&);
 
 type_base_sptr
-type_or_void(const type_base_sptr, const environment*);
+type_or_void(const type_base_sptr, const environment&);
 
 type_base_sptr
 canonicalize(type_base_sptr);
diff --git a/include/abg-ir.h b/include/abg-ir.h
index 4892f0e2..4272a13c 100644
--- a/include/abg-ir.h
+++ b/include/abg-ir.h
@@ -649,7 +649,7 @@ class translation_unit : public traversable_base
   std::unique_ptr<priv> priv_;
 
   // Forbidden
-  translation_unit() = delete;
+  translation_unit();
 
 public:
   /// Convenience typedef for a shared pointer on a @ref global_scope.
@@ -689,21 +689,15 @@ public:
   };
 
 public:
-  translation_unit(const ir::environment*	env,
+  translation_unit(const ir::environment&	env,
 		   const std::string&		path,
 		   char			address_size = 0);
 
   virtual ~translation_unit();
 
-  const environment*
+  const environment&
   get_environment() const;
 
-  environment*
-  get_environment();
-
-  void
-  set_environment(const environment*);
-
   language
   get_language() const;
 
@@ -929,7 +923,7 @@ private:
 
   elf_symbol();
 
-  elf_symbol(const environment* e,
+  elf_symbol(const environment& e,
 	     size_t		i,
 	     size_t		s,
 	     const string&	n,
@@ -952,30 +946,24 @@ private:
 public:
 
   static elf_symbol_sptr
-  create();
-
-  static elf_symbol_sptr
-  create(const environment* e,
-	 size_t		    i,
-	 size_t		    s,
-	 const string&	    n,
-	 type		    t,
-	 binding	    b,
-	 bool		    d,
-	 bool		    c,
-	 const version&	    ve,
-	 visibility	    vi,
-	 bool		    is_in_ksymtab = false,
+  create(const environment&	e,
+	 size_t		i,
+	 size_t		s,
+	 const string&		n,
+	 type			t,
+	 binding		b,
+	 bool			d,
+	 bool			c,
+	 const version&	ve,
+	 visibility		vi,
+	 bool			is_in_ksymtab = false,
 	 const abg_compat::optional<uint64_t>&		crc = {},
 	 const abg_compat::optional<std::string>&	ns = {},
-	 bool		    is_suppressed = false);
+	 bool						is_suppressed = false);
 
-  const environment*
+  const environment&
   get_environment() const;
 
-  void
-  set_environment(const environment*) const;
-
   size_t
   get_index() const;
 
@@ -1340,6 +1328,7 @@ class type_or_decl_base : public ir_traversable_base
   mutable std::unique_ptr<priv> priv_;
 
   type_or_decl_base();
+  type_or_decl_base(const type_or_decl_base&);
 
 protected:
 
@@ -1399,13 +1388,14 @@ protected:
 
   void hashing_started(bool) const;
 
+  type_or_decl_base&
+  operator=(const type_or_decl_base&);
+
 public:
 
-  type_or_decl_base(const environment*,
+  type_or_decl_base(const environment&,
 		    enum type_or_decl_kind k = ABSTRACT_TYPE_OR_DECL);
 
-  type_or_decl_base(const type_or_decl_base&);
-
   virtual ~type_or_decl_base();
 
   bool
@@ -1414,15 +1404,9 @@ public:
   void
   set_is_artificial(bool);
 
-  const environment*
+  const environment&
   get_environment() const;
 
-  environment*
-  get_environment();
-
-  void
-  set_environment(const environment*);
-
   void
   set_artificial_location(const location &);
 
@@ -1447,9 +1431,6 @@ public:
   translation_unit*
   get_translation_unit();
 
-  type_or_decl_base&
-  operator=(const type_or_decl_base&);
-
   virtual bool
   traverse(ir_node_visitor&);
 
@@ -1511,14 +1492,6 @@ operator==(const type_or_decl_base_sptr&, const type_or_decl_base_sptr&);
 bool
 operator!=(const type_or_decl_base_sptr&, const type_or_decl_base_sptr&);
 
-void
-set_environment_for_artifact(type_or_decl_base* artifact,
-			     const environment* env);
-
-void
-set_environment_for_artifact(type_or_decl_base_sptr artifact,
-			     const environment* env);
-
 /// The base type of all declarations.
 class decl_base : public virtual type_or_decl_base
 {
@@ -1591,23 +1564,22 @@ protected:
 
   void
   set_context_rel(context_rel *c);
+  decl_base(const decl_base&);
 
 public:
-  decl_base(const environment* e,
+  decl_base(const environment& e,
 	    const string& name,
 	    const location& locus,
 	    const string& mangled_name = "",
 	    visibility vis = VISIBILITY_DEFAULT);
 
-  decl_base(const environment* e,
+  decl_base(const environment& e,
 	    const interned_string& name,
 	    const location& locus,
 	    const interned_string& mangled_name = interned_string(),
 	    visibility vis = VISIBILITY_DEFAULT);
 
-  decl_base(const environment*, const location&);
-
-  decl_base(const decl_base&);
+  decl_base(const environment&, const location&);
 
   virtual bool
   operator==(const decl_base&) const;
@@ -1821,11 +1793,11 @@ protected:
 public:
   struct hash;
 
-  scope_decl(const environment* env,
+  scope_decl(const environment& env,
 	     const string& name, const location& locus,
 	     visibility	vis = VISIBILITY_DEFAULT);
 
-  scope_decl(const environment* env, location& l);
+  scope_decl(const environment& env, location& l);
 
   virtual size_t
   get_hash() const;
@@ -2000,7 +1972,7 @@ public:
   /// runtime type of the type pointed to.
   struct shared_ptr_hash;
 
-  type_base(const environment* e, size_t s, size_t a);
+  type_base(const environment& e, size_t s, size_t a);
 
   friend type_base_sptr canonicalize(type_base_sptr);
 
@@ -2104,7 +2076,7 @@ public:
   /// Facility to hash instance of type_decl
   struct hash;
 
-  type_decl(const environment*	env,
+  type_decl(const environment&	env,
 	    const string&	name,
 	    size_t		size_in_bits,
 	    size_t		alignment_in_bits,
@@ -2159,7 +2131,7 @@ public:
   /// Hasher for instances of scope_type_decl
   struct hash;
 
-  scope_type_decl(const environment* env, const string& name,
+  scope_type_decl(const environment& env, const string& name,
 		  size_t size_in_bits, size_t alignment_in_bits,
 		  const location& locus, visibility vis = VISIBILITY_DEFAULT);
 
@@ -2180,7 +2152,7 @@ class namespace_decl : public scope_decl
 {
 public:
 
-  namespace_decl(const environment* env, const string& name,
+  namespace_decl(const environment& env, const string& name,
 		 const location& locus, visibility vis = VISIBILITY_DEFAULT);
 
   virtual string
@@ -2234,7 +2206,7 @@ public:
 
   qualified_type_def(type_base_sptr type, CV quals, const location& locus);
 
-  qualified_type_def(environment* env, CV quals, const location& locus);
+  qualified_type_def(const environment& env, CV quals, const location& locus);
 
   virtual size_t
   get_size_in_bits() const;
@@ -2335,10 +2307,9 @@ public:
   pointer_type_def(const type_base_sptr& pointed_to_type, size_t size_in_bits,
 		   size_t alignment_in_bits, const location& locus);
 
-  pointer_type_def(environment* env, size_t size_in_bits,
+  pointer_type_def(const environment& env, size_t size_in_bits,
 		   size_t alignment_in_bits, const location& locus);
 
-
   void
   set_pointed_to_type(const type_base_sptr&);
 
@@ -2400,7 +2371,7 @@ public:
 		     bool lvalue, size_t size_in_bits,
 		     size_t alignment_in_bits, const location& locus);
 
-  reference_type_def(const environment* env, bool lvalue, size_t size_in_bits,
+  reference_type_def(const environment& env, bool lvalue, size_t size_in_bits,
 		     size_t alignment_in_bits, const location& locus);
 
   void
@@ -2522,7 +2493,7 @@ public:
     /// Hasher for an instance of array::subrange
     struct hash;
 
-    subrange_type(const environment*	env,
+    subrange_type(const environment&	env,
 		  const string&	name,
 		  bound_value		lower_bound,
 		  bound_value		upper_bound,
@@ -2530,14 +2501,14 @@ public:
 		  const location&	loc,
 		  translation_unit::language l = translation_unit::LANG_C11);
 
-    subrange_type(const environment* env,
+    subrange_type(const environment& env,
 		  const string& name,
 		  bound_value lower_bound,
 		  bound_value upper_bound,
 		  const location& loc,
 		  translation_unit::language l = translation_unit::LANG_C11);
 
-    subrange_type(const environment* env,
+    subrange_type(const environment& env,
 		  const string& name,
 		  bound_value upper_bound,
 		  const location& loc,
@@ -2603,7 +2574,7 @@ public:
 		 const std::vector<subrange_sptr>& subs,
 		 const location& locus);
 
-  array_type_def(environment* env,
+  array_type_def(const environment& env,
 		 const std::vector<subrange_sptr>& subs,
 		 const location& locus);
 
@@ -2761,7 +2732,7 @@ public:
 
   ~enumerator();
 
-  enumerator(const environment* env, const string& name, int64_t value);
+  enumerator(const string& name, int64_t value);
 
   enumerator(const enumerator&);
 
@@ -2774,13 +2745,10 @@ public:
   bool
   operator!=(const enumerator& other) const;
 
-  const environment*
-  get_environment() const;
-
-  const interned_string&
+  const string&
   get_name() const;
 
-  const interned_string&
+  const string&
   get_qualified_name(bool internal = false) const;
 
   void
@@ -2823,7 +2791,7 @@ public:
 	       visibility vis = VISIBILITY_DEFAULT);
 
   typedef_decl(const string& name,
-	       environment* env,
+	       const environment& env,
 	       const location& locus,
 	       const string& mangled_name = "",
 	       visibility vis = VISIBILITY_DEFAULT);
@@ -3320,7 +3288,7 @@ public:
 		size_t		size_in_bits,
 		size_t		alignment_in_bits);
 
-  function_type(const environment*	env,
+  function_type(const environment&	env,
 		size_t		size_in_bits,
 		size_t		alignment_in_bits);
 
@@ -3415,7 +3383,7 @@ public:
 	      size_t size_in_bits,
 	      size_t alignment_in_bits);
 
-  method_type(const environment* env,
+  method_type(const environment& env,
 	      size_t size_in_bits,
 	      size_t alignment_in_bits);
 
@@ -3452,7 +3420,7 @@ public:
   /// Hasher.
   struct hash;
 
-  template_decl(const environment*	env,
+  template_decl(const environment&	env,
 		const string&		name,
 		const location&	locus,
 		visibility		vis = VISIBILITY_DEFAULT);
@@ -3683,7 +3651,7 @@ public:
   struct hash;
   struct shared_ptr_hash;
 
-  function_tdecl(const environment*	env,
+  function_tdecl(const environment&	env,
 		 const location&	locus,
 		 visibility		vis = VISIBILITY_DEFAULT,
 		 binding		bind = BINDING_NONE);
@@ -3732,7 +3700,7 @@ public:
   struct hash;
   struct shared_ptr_hash;
 
-  class_tdecl(const environment* env, const location& locus,
+  class_tdecl(const environment& env, const location& locus,
 	      visibility vis = VISIBILITY_DEFAULT);
 
   class_tdecl(class_decl_sptr	pattern,
@@ -3953,17 +3921,17 @@ public:
   typedef unordered_map<string, method_decl_sptr> string_mem_fn_sptr_map_type;
   /// @}
 
-  class_or_union(const environment* env, const string& name,
+  class_or_union(const environment& env, const string& name,
 		 size_t size_in_bits, size_t align_in_bits,
 		 const location& locus, visibility vis,
 		 member_types& mbrs, data_members& data_mbrs,
 		 member_functions& member_fns);
 
-  class_or_union(const environment* env, const string& name,
+  class_or_union(const environment& env, const string& name,
 		 size_t size_in_bits, size_t align_in_bits,
 		 const location& locus, visibility vis);
 
-  class_or_union(const environment* env, const string& name,
+  class_or_union(const environment& env, const string& name,
 		 bool is_declaration_only = true);
 
   virtual void
@@ -4159,30 +4127,30 @@ private:
 
 public:
 
-  class_decl(const environment* env, const string& name,
+  class_decl(const environment& env, const string& name,
 	     size_t size_in_bits, size_t align_in_bits,
 	     bool is_struct, const location& locus,
 	     visibility vis, base_specs& bases,
 	     member_types& mbrs, data_members& data_mbrs,
 	     member_functions& member_fns);
 
-  class_decl(const environment* env, const string& name,
+  class_decl(const environment& env, const string& name,
 	     size_t size_in_bits, size_t align_in_bits,
 	     bool is_struct, const location& locus,
 	     visibility vis, base_specs& bases,
 	     member_types& mbrs, data_members& data_mbrs,
 	     member_functions& member_fns, bool is_anonymous);
 
-  class_decl(const environment* env, const string& name,
+  class_decl(const environment& env, const string& name,
 	     size_t size_in_bits, size_t align_in_bits,
 	     bool is_struct, const location& locus, visibility vis);
 
-  class_decl(const environment* env, const string& name,
+  class_decl(const environment& env, const string& name,
 	     size_t size_in_bits, size_t align_in_bits,
 	     bool is_struct, const location& locus,
 	     visibility vis, bool is_anonymous);
 
-  class_decl(const environment* env, const string& name, bool is_struct,
+  class_decl(const environment& env, const string& name, bool is_struct,
 	     bool is_declaration_only = true);
 
   virtual string
@@ -4376,26 +4344,26 @@ class union_decl : public class_or_union
 
 public:
 
-  union_decl(const environment* env, const string& name,
+  union_decl(const environment& env, const string& name,
 	     size_t size_in_bits, const location& locus,
 	     visibility vis, member_types& mbrs,
 	     data_members& data_mbrs, member_functions& member_fns);
 
-  union_decl(const environment* env, const string& name,
+  union_decl(const environment& env, const string& name,
 	     size_t size_in_bits, const location& locus,
 	     visibility vis, member_types& mbrs,
 	     data_members& data_mbrs, member_functions& member_fns,
 	     bool is_anonymous);
 
-  union_decl(const environment* env, const string& name,
+  union_decl(const environment& env, const string& name,
 	     size_t size_in_bits, const location& locus,
 	     visibility vis);
 
-  union_decl(const environment* env, const string& name,
+  union_decl(const environment& env, const string& name,
 	     size_t size_in_bits, const location& locus,
 	     visibility vis, bool is_anonymous);
 
-  union_decl(const environment* env, const string& name,
+  union_decl(const environment& env, const string& name,
 	     bool is_declaration_only = true);
 
   virtual string
diff --git a/include/abg-reader.h b/include/abg-reader.h
index 624311bc..d89c6458 100644
--- a/include/abg-reader.h
+++ b/include/abg-reader.h
@@ -17,86 +17,72 @@
 #include <istream>
 #include "abg-corpus.h"
 #include "abg-suppression.h"
+#include "abg-fe-iface.h"
 
 namespace abigail
 {
 
-namespace xml_reader
+namespace abixml_reader
 {
 
 using namespace abigail::ir;
 
-class read_context;
-
 translation_unit_sptr
 read_translation_unit_from_file(const std::string&	file_path,
-				environment*		env);
+				environment&		env);
 
 translation_unit_sptr
 read_translation_unit_from_buffer(const std::string&	file_path,
-				  environment*		env);
+				  environment&		env);
 
 translation_unit_sptr
 read_translation_unit_from_istream(std::istream*	in,
-				   environment*	env);
+				   environment&	env);
 
 translation_unit_sptr
-read_translation_unit(read_context&);
-
-/// A convenience typedef for a shared pointer to read_context.
-typedef shared_ptr<read_context> read_context_sptr;
+read_translation_unit(fe_iface&);
 
-read_context_sptr
-create_native_xml_read_context(const string& path, environment *env);
+ abigail::fe_iface_sptr
+create_abixml_reader(const string& path, environment& env);
 
-read_context_sptr
-create_native_xml_read_context(std::istream* in, environment* env);
-
-const string&
-read_context_get_path(const read_context&);
+fe_iface_sptr
+create_abixml_reader(std::istream* in, environment& env);
 
 corpus_sptr
-read_corpus_from_native_xml(std::istream* in,
-			    environment*  env);
+read_corpus_from_abixml(std::istream* in,
+			environment&  env);
 
 corpus_sptr
-read_corpus_from_native_xml_file(const string& path,
-				 environment*  env);
-
-corpus_sptr
-read_corpus_from_input(read_context& ctxt);
+read_corpus_from_abixml_file(const string& path,
+			     environment&  env);
 
 corpus_group_sptr
-read_corpus_group_from_input(read_context& ctxt);
+read_corpus_group_from_input(fe_iface& ctxt);
 
 corpus_group_sptr
-read_corpus_group_from_native_xml(std::istream* in,
-				  environment*  env);
+read_corpus_group_from_abixml(std::istream* in,
+			      environment&  env);
 
 corpus_group_sptr
-read_corpus_group_from_native_xml_file(const string& path,
-				       environment*  env);
-
-void
-add_read_context_suppressions(read_context& ctxt,
-			      const suppr::suppressions_type& supprs);
+read_corpus_group_from_abixml_file(const string& path,
+				   environment&  env);
 
 void
-consider_types_not_reachable_from_public_interfaces(read_context& ctxt,
+consider_types_not_reachable_from_public_interfaces(fe_iface& ctxt,
 						    bool flag);
 
 #ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
 vector<type_base_sptr>*
-get_types_from_type_id(read_context&, const string&);
+get_types_from_type_id(fe_iface&, const string&);
 
 unordered_map<type_or_decl_base*, vector<type_or_decl_base*>>*
-get_artifact_used_by_relation_map(read_context&);
+get_artifact_used_by_relation_map(fe_iface&);
 #endif
-}//end xml_reader
+}//end abixml_reader
 
 #ifdef WITH_DEBUG_SELF_COMPARISON
 bool
-load_canonical_type_ids(xml_reader::read_context& ctxt,
+load_canonical_type_ids(fe_iface& ctxt,
 			const string& file_path);
 #endif
 }//end namespace abigail
diff --git a/include/abg-suppression.h b/include/abg-suppression.h
index 609fba75..90575f73 100644
--- a/include/abg-suppression.h
+++ b/include/abg-suppression.h
@@ -16,6 +16,8 @@
 namespace abigail
 {
 
+class fe_iface;
+
 /// @brief an engine to suppress the parts of the result of comparing
 /// two sets of ABI artifacts.
 ///
@@ -116,6 +118,12 @@ public:
 					 const suppression_base& suppr);
 }; // end class suppression_base
 
+/// Convenience typedef for a shared pointer to a @ref suppression.
+typedef shared_ptr<suppression_base> suppression_sptr;
+
+/// Convenience typedef for a vector of @ref suppression_sptr
+typedef vector<suppression_sptr> suppressions_type;
+
 void
 read_suppressions(std::istream& input,
 		  suppressions_type& suppressions);
@@ -821,8 +829,67 @@ is_private_type_suppr_spec(const type_suppression&);
 
 bool
 is_private_type_suppr_spec(const suppression_sptr& s);
+
+bool
+suppression_can_match(const fe_iface&,
+		      const suppression_base&);
+
+bool
+suppression_matches_function_name(const fe_iface&,
+				  const suppr::function_suppression&,
+				  const string&);
+
+bool
+suppression_matches_function_sym_name(const fe_iface&,
+				      const suppr::function_suppression& s,
+				      const string& fn_linkage_name);
+
+bool
+suppression_matches_variable_name(const fe_iface&,
+				  const suppr::variable_suppression& s,
+				  const string& var_name);
+
+bool
+suppression_matches_variable_sym_name(const fe_iface&,
+				      const suppr::variable_suppression&,
+				      const string&);
+
+bool
+suppression_matches_type_name_or_location(const fe_iface&,
+					  const suppr::type_suppression&,
+					  const string&,
+					  const location&);
+
+bool
+is_elf_symbol_suppressed(const fe_iface&,
+			 const elf_symbol_sptr& symbol);
+
+bool
+is_elf_symbol_suppressed(const fe_iface&,
+			 const string& sym_name,
+			 elf_symbol::type sym_type);
+
+bool
+is_function_suppressed(const fe_iface&	fe,
+		       const string&		fn_name,
+		       const string&		fn_linkage_name,
+		       bool			require_drop_property = false);
+
+bool
+is_variable_suppressed(const fe_iface&	fe,
+		       const string&	var_name,
+		       const string&	var_linkage_name,
+		       bool			require_drop_property = false);
+
+bool
+is_type_suppressed(const fe_iface&	fe,
+		   const string&	type_name,
+		   const location&	type_location,
+		   bool&		type_is_private,
+		   bool			require_drop_property = false);
 } // end namespace suppr
 
+
 } // end namespace abigail
 
 #endif //__ABG_SUPPRESSION_H__
diff --git a/include/abg-tools-utils.h b/include/abg-tools-utils.h
index 27bbfefe..9dc9b8d3 100644
--- a/include/abg-tools-utils.h
+++ b/include/abg-tools-utils.h
@@ -15,6 +15,7 @@
 #include <set>
 #include <string>
 #include "abg-suppression.h"
+#include "abg-elf-based-reader.h"
 
 namespace abigail
 {
@@ -36,6 +37,10 @@ const char* get_anonymous_enum_internal_name_prefix();
 
 bool file_exists(const string&);
 bool is_regular_file(const string&);
+bool file_has_dwarf_debug_info(const string& elf_file_path,
+			       const vector<char**>& debug_info_root_paths);
+bool file_has_ctf_debug_info(const string& elf_file_path,
+			     const vector<char**>& debug_info_root_paths);
 bool is_dir(const string&);
 bool dir_exists(const string&);
 bool dir_is_empty(const string &);
@@ -311,8 +316,14 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 					  vector<string>&	kabi_wl_paths,
 					  suppr::suppressions_type&	supprs,
 					  bool				verbose,
-					  environment_sptr&		env,
+					  environment&			env,
 					  corpus::origin	origin = corpus::DWARF_ORIGIN);
+
+elf_based_reader_sptr
+create_best_elf_based_reader(const string& elf_file_path,
+			     const vector<char**>& debug_info_root_paths,
+			     environment& env);
+
 }// end namespace tools_utils
 
 /// A macro that expands to aborting the program when executed.
diff --git a/include/abg-writer.h b/include/abg-writer.h
index ab01b486..58f60b74 100644
--- a/include/abg-writer.h
+++ b/include/abg-writer.h
@@ -36,7 +36,7 @@ class write_context;
 typedef shared_ptr<write_context> write_context_sptr;
 
 write_context_sptr
-create_write_context(const environment *env,
+create_write_context(const environment& env,
 		     ostream& output_stream);
 
 void
diff --git a/src/Makefile.am b/src/Makefile.am
index 1748f0b8..70cc04a5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -26,8 +26,10 @@ abg-suppression-priv.h			\
 abg-suppression.cc			\
 abg-comp-filter.cc			\
 abg-reader.cc				\
-abg-elf-reader-common.cc		\
 abg-dwarf-reader.cc			\
+abg-fe-iface.cc				\
+abg-elf-based-reader.cc			\
+abg-elf-reader.cc			\
 abg-libxml-utils.cc			\
 abg-hash.cc				\
 abg-writer.cc				\
diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc
index 6e3b2b55..0868d384 100644
--- a/src/abg-comparison.cc
+++ b/src/abg-comparison.cc
@@ -3133,8 +3133,6 @@ compute_diff(const decl_base_sptr	first,
   if (!first || !second)
     return diff_sptr();
 
-  ABG_ASSERT(first->get_environment() == second->get_environment());
-
   diff_sptr d;
   if (is_type(first) && is_type(second))
     d = compute_diff_for_types(first, second, ctxt);
@@ -3165,9 +3163,6 @@ compute_diff(const type_base_sptr	first,
   decl_base_sptr f = get_type_declaration(first),
     s = get_type_declaration(second);
 
-  if (first && second)
-    ABG_ASSERT(first->get_environment() == second->get_environment());
-
   diff_sptr d = compute_diff_for_types(f,s, ctxt);
   ABG_ASSERT(d);
   return d;
@@ -3317,9 +3312,6 @@ compute_diff(const var_decl_sptr	first,
 	     const var_decl_sptr	second,
 	     diff_context_sptr		ctxt)
 {
-  if (first && second)
-    ABG_ASSERT(first->get_environment() == second->get_environment());
-
   var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
   ctxt->initialize_canonical_diff(d);
 
@@ -3451,9 +3443,6 @@ compute_diff(pointer_type_def_sptr	first,
 	     pointer_type_def_sptr	second,
 	     diff_context_sptr		ctxt)
 {
-  if (first && second)
-    ABG_ASSERT(first->get_environment() == second->get_environment());
-
   diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
 				       second->get_pointed_to_type(),
 				       ctxt);
@@ -3607,9 +3596,6 @@ compute_diff(array_type_def_sptr	first,
 	     array_type_def_sptr	second,
 	     diff_context_sptr		ctxt)
 {
-  if (first && second)
-    ABG_ASSERT(first->get_environment() == second->get_environment());
-
   diff_sptr d = compute_diff_for_types(first->get_element_type(),
 				       second->get_element_type(),
 				       ctxt);
@@ -3742,9 +3728,6 @@ compute_diff(reference_type_def_sptr	first,
 	     reference_type_def_sptr	second,
 	     diff_context_sptr		ctxt)
 {
-  if (first && second)
-    ABG_ASSERT(first->get_environment() == second->get_environment());
-
   diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
 				       second->get_pointed_to_type(),
 				       ctxt);
@@ -3892,9 +3875,6 @@ compute_diff(const qualified_type_def_sptr	first,
 	     const qualified_type_def_sptr	second,
 	     diff_context_sptr			ctxt)
 {
-  if (first && second)
-    ABG_ASSERT(first->get_environment() == second->get_environment());
-
   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
 				       second->get_underlying_type(),
 				       ctxt);
@@ -4110,9 +4090,6 @@ compute_diff(const enum_type_decl_sptr first,
 	     const enum_type_decl_sptr second,
 	     diff_context_sptr ctxt)
 {
-  if (first && second)
-    ABG_ASSERT(first->get_environment() == second->get_environment());
-
   diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
 					second->get_underlying_type(),
 					ctxt);
@@ -5596,9 +5573,6 @@ compute_diff(const class_decl_sptr	first,
 	     const class_decl_sptr	second,
 	     diff_context_sptr		ctxt)
 {
-  if (first && second)
-    ABG_ASSERT(first->get_environment() == second->get_environment());
-
   class_decl_sptr f = is_class_type(look_through_decl_only_class(first)),
     s = is_class_type(look_through_decl_only_class(second));
 
@@ -5821,15 +5795,6 @@ compute_diff(const class_decl::base_spec_sptr	first,
 	     const class_decl::base_spec_sptr	second,
 	     diff_context_sptr			ctxt)
 {
-  if (first && second)
-    {
-      ABG_ASSERT(first->get_environment() == second->get_environment());
-      ABG_ASSERT(first->get_base_class()->get_environment()
-	     == second->get_base_class()->get_environment());
-      ABG_ASSERT(first->get_environment()
-	     == first->get_base_class()->get_environment());
-    }
-
   class_diff_sptr cl = compute_diff(first->get_base_class(),
 				    second->get_base_class(),
 				    ctxt);
@@ -5945,9 +5910,6 @@ compute_diff(const union_decl_sptr	first,
 	     const union_decl_sptr	second,
 	     diff_context_sptr	ctxt)
 {
-  if (first && second)
-    ABG_ASSERT(first->get_environment() == second->get_environment());
-
   union_diff_sptr changes(new union_diff(first, second, ctxt));
 
   ctxt->initialize_canonical_diff(changes);
@@ -6449,9 +6411,6 @@ compute_diff(const scope_decl_sptr	first,
 {
   ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
 
-  if (first && second)
-    ABG_ASSERT(first->get_environment() == second->get_environment());
-
   compute_diff(first->get_member_decls().begin(),
 	       first->get_member_decls().end(),
 	       second->get_member_decls().begin(),
@@ -6482,10 +6441,6 @@ compute_diff(const scope_decl_sptr	first_scope,
 	     const scope_decl_sptr	second_scope,
 	     diff_context_sptr		ctxt)
 {
-  if (first_scope && second_scope)
-    ABG_ASSERT(first_scope->get_environment()
-	   == second_scope->get_environment());
-
   scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
   d = compute_diff(first_scope, second_scope, d, ctxt);
   ctxt->initialize_canonical_diff(d);
@@ -6632,8 +6587,6 @@ compute_diff(const function_decl::parameter_sptr	first,
   if (!first || !second)
     return fn_parm_diff_sptr();
 
-  ABG_ASSERT(first->get_environment() == second->get_environment());
-
   fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
   ctxt->initialize_canonical_diff(result);
 
@@ -6930,8 +6883,6 @@ compute_diff(const function_type_sptr	first,
       return function_type_diff_sptr();
     }
 
-  ABG_ASSERT(first->get_environment() == second->get_environment());
-
   function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
 
   diff_utils::compute_diff(first->get_first_parm(),
@@ -7072,8 +7023,6 @@ compute_diff(const function_decl_sptr first,
       return function_decl_diff_sptr();
     }
 
-  ABG_ASSERT(first->get_environment() == second->get_environment());
-
   function_type_diff_sptr type_diff = compute_diff(first->get_type(),
 						   second->get_type(),
 						   ctxt);
@@ -7196,9 +7145,6 @@ compute_diff(const type_decl_sptr	first,
 	     const type_decl_sptr	second,
 	     diff_context_sptr		ctxt)
 {
-  if (first && second)
-    ABG_ASSERT(first->get_environment() == second->get_environment());
-
   type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
 
   // We don't need to actually compute a diff here as a type_decl
@@ -7349,9 +7295,6 @@ compute_diff(const typedef_decl_sptr	first,
 	     const typedef_decl_sptr	second,
 	     diff_context_sptr		ctxt)
 {
-  if (first && second)
-    ABG_ASSERT(first->get_environment() == second->get_environment());
-
   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
 				       second->get_underlying_type(),
 				       ctxt);
@@ -7470,8 +7413,6 @@ compute_diff(const translation_unit_sptr	first,
 {
   ABG_ASSERT(first && second);
 
-  ABG_ASSERT(first->get_environment() == second->get_environment());
-
   if (!ctxt)
     ctxt.reset(new diff_context);
 
@@ -10929,10 +10870,6 @@ compute_diff(const corpus_sptr	f,
 
   ABG_ASSERT(f && s);
 
-  // We can only compare two corpora that were built out of the same
-  // environment.
-  ABG_ASSERT(f->get_environment() == s->get_environment());
-
   if (!ctxt)
     ctxt.reset(new diff_context);
 
@@ -12272,11 +12209,11 @@ is_diff_of_variadic_parameter_type(const diff* d)
     return false;
 
   type_base_sptr t = is_type(d->first_subject());
-  if (t && t->get_environment()->is_variadic_parameter_type(t))
+  if (t && t->get_environment().is_variadic_parameter_type(t))
     return true;
 
   t = is_type(d->second_subject());
-  if (t && t->get_environment()->is_variadic_parameter_type(t))
+  if (t && t->get_environment().is_variadic_parameter_type(t))
     return true;
 
   return false;
diff --git a/src/abg-corpus-priv.h b/src/abg-corpus-priv.h
index 8719be56..0b40d800 100644
--- a/src/abg-corpus-priv.h
+++ b/src/abg-corpus-priv.h
@@ -403,12 +403,12 @@ public:
   ///
   /// @param fn the function to add to the set of exported functions.
   void
-  add_fn_to_exported(function_decl* fn)
+  add_fn_to_exported(const function_decl* fn)
   {
     if (!fn_is_in_id_fns_map(fn))
       {
-	fns_.push_back(fn);
-	add_fn_to_id_fns_map(fn);
+	fns_.push_back(const_cast<function_decl*>(fn));
+	add_fn_to_id_fns_map(const_cast<function_decl*>(fn));
       }
   }
 
@@ -416,13 +416,13 @@ public:
   ///
   /// @param fn the variable to add to the set of exported variables.
   void
-  add_var_to_exported(var_decl* var)
+  add_var_to_exported(const var_decl* var)
   {
     const string& id = get_id(*var);
     if (!var_id_is_in_id_var_map(id))
       {
-	vars_.push_back(var);
-	add_var_to_map(var);
+	vars_.push_back(const_cast<var_decl*>(var));
+	add_var_to_map(const_cast<var_decl*>(var));
       }
   }
 
@@ -667,7 +667,7 @@ struct corpus::priv
   mutable unordered_map<string, type_base_sptr> canonical_types_;
   string					format_major_version_number_;
   string					format_minor_version_number_;
-  environment*					env;
+  const environment&				env;
   corpus_group*				group;
   corpus::exported_decls_builder_sptr		exported_decls_builder;
   corpus::origin				origin_;
@@ -717,8 +717,8 @@ private:
   mutable abg_compat::optional<elf_symbols> unrefed_fun_symbols;
 
 public:
-  priv(const string &	p,
-       environment*	e)
+  priv(const string &		p,
+       const environment&	e)
     : env(e),
       group(),
       origin_(ARTIFICIAL_ORIGIN),
diff --git a/src/abg-corpus.cc b/src/abg-corpus.cc
index 0b23667f..8c1e6158 100644
--- a/src/abg-corpus.cc
+++ b/src/abg-corpus.cc
@@ -133,7 +133,7 @@ corpus::exported_decls_builder::exported_variables()
 ///
 /// @param fn the function to add the set of exported functions.
 void
-corpus::exported_decls_builder::maybe_add_fn_to_exported_fns(function_decl* fn)
+corpus::exported_decls_builder::maybe_add_fn_to_exported_fns(const function_decl* fn)
 {
   if (!fn->get_is_in_public_symbol_table())
     return;
@@ -156,7 +156,7 @@ corpus::exported_decls_builder::maybe_add_fn_to_exported_fns(function_decl* fn)
 ///
 /// @param fn the variable to add the set of exported variables.
 void
-corpus::exported_decls_builder::maybe_add_var_to_exported_vars(var_decl* var)
+corpus::exported_decls_builder::maybe_add_var_to_exported_vars(const var_decl* var)
 {
   if (!var->get_is_in_public_symbol_table())
     return;
@@ -596,7 +596,7 @@ corpus::priv::~priv()
 /// @param env the environment of the corpus.
 ///
 /// @param path the path to the file containing the ABI corpus.
-corpus::corpus(ir::environment* env, const string& path)
+corpus::corpus(const ir::environment& env, const string& path)
 {
   priv_.reset(new priv(path, env));
   init_format_version();
@@ -607,31 +607,11 @@ corpus::~corpus() = default;
 /// Getter of the enviroment of the corpus.
 ///
 /// @return the environment of this corpus.
-const environment*
+const environment&
 corpus::get_environment() const
 {return priv_->env;}
 
-/// Getter of the enviroment of the corpus.
-///
-/// @return the environment of this corpus.
-environment*
-corpus::get_environment()
-{return priv_->env;}
-
-/// Setter of the environment of this corpus.
-///
-/// @param e the new environment.
-void
-corpus::set_environment(environment* e)
-{
-  priv_->env = e;
-  init_format_version();
-}
-
-/// Add a translation unit to the current ABI Corpus. Next time
-/// corpus::save is called, all the translation unit that got added to
-/// the corpus are going to be serialized on disk in the file
-/// associated to the current corpus.
+/// Add a translation unit to the current ABI Corpus.
 ///
 /// Note that two translation units with the same path (as returned by
 /// translation_unit::get_path) cannot be added to the same @ref
@@ -639,13 +619,8 @@ corpus::set_environment(environment* e)
 ///
 /// @param tu the new translation unit to add.
 void
-corpus::add(const translation_unit_sptr tu)
+corpus::add(const translation_unit_sptr& tu)
 {
-  if (!tu->get_environment())
-    tu->set_environment(get_environment());
-
-  ABG_ASSERT(tu->get_environment() == get_environment());
-
   ABG_ASSERT(priv_->members.insert(tu).second);
 
   if (!tu->get_absolute_path().empty())
@@ -741,7 +716,7 @@ void
 corpus::record_type_as_reachable_from_public_interfaces(const type_base& t)
 {
   string repr = get_pretty_representation(&t, /*internal=*/true);
-  interned_string s = t.get_environment()->intern(repr);
+  interned_string s = t.get_environment().intern(repr);
   priv_->get_public_types_pretty_representations()->insert(s);
 }
 
@@ -759,7 +734,7 @@ bool
 corpus::type_is_reachable_from_public_interfaces(const type_base& t) const
 {
   string repr = get_pretty_representation(&t, /*internal=*/true);
-  interned_string s = t.get_environment()->intern(repr);
+  interned_string s = t.get_environment().intern(repr);
 
   return (priv_->get_public_types_pretty_representations()->find(s)
 	  !=  priv_->get_public_types_pretty_representations()->end());
@@ -839,13 +814,10 @@ corpus::set_group(corpus_group* g)
 void
 corpus::init_format_version()
 {
-  if (priv_->env)
-    {
-      set_format_major_version_number
-	(priv_->env->get_config().get_format_major_version_number());
-      set_format_minor_version_number
-	(priv_->env->get_config().get_format_minor_version_number());
-    }
+  set_format_major_version_number
+    (priv_->env.get_config().get_format_major_version_number());
+  set_format_minor_version_number
+    (priv_->env.get_config().get_format_minor_version_number());
 }
 
 /// Getter for the origin of the corpus.
@@ -1013,7 +985,9 @@ corpus::is_empty() const
   return (members_empty
 	  && (!get_symtab() || !get_symtab()->has_symbols())
 	  && priv_->soname.empty()
-	  && priv_->needed.empty());
+	  && priv_->needed.empty()
+	  && priv_->architecture_name.empty()
+	  && !priv_->group);
 }
 
 /// Compare the current @ref corpus against another one.
@@ -1690,8 +1664,12 @@ struct corpus_group::priv
   }
 }; // end corpus_group::priv
 
-/// Default constructor of the @ref corpus_group type.
-corpus_group::corpus_group(environment* env, const string& path = "")
+/// Constructor of the @ref corpus_group type.
+///
+/// @param env the environment of the @ref corpus_group.
+///
+/// @param path the path to the file represented by the corpus group.
+corpus_group::corpus_group(const environment& env, const string& path = "")
   : corpus(env, path), priv_(new priv)
 {}
 
@@ -1708,15 +1686,6 @@ corpus_group::add_corpus(const corpus_sptr& corp)
   if (!corp)
     return;
 
-  // Ensure the new environment patches the current one.
-  if (const environment* cur_env = get_environment())
-    {
-      if (environment* corp_env = corp->get_environment())
-	ABG_ASSERT(cur_env == corp_env);
-    }
-  else
-    set_environment(corp->get_environment());
-
   // Ensure the new architecture name matches the current one.
   string cur_arch = get_architecture_name(),
     corp_arch = corp->get_architecture_name();
diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index e307fcd7..cabb919e 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -23,17 +23,18 @@
 
 #include "abg-internal.h"
 #include "abg-ir-priv.h"
-#include "abg-elf-helpers.h"
+#include "abg-symtab-reader.h"
 
+
+#include "abg-internal.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-elf-based-reader.h"
 #include "abg-corpus.h"
-#include "abg-symtab-reader.h"
 #include "abg-tools-utils.h"
+#include "abg-elf-helpers.h"
 
 ABG_END_EXPORT_DECLARATIONS
 // </headers defining libabigail's API>
@@ -46,16 +47,104 @@ using std::dynamic_pointer_cast;
 using abigail::tools_utils::dir_name;
 using abigail::tools_utils::file_exists;
 
-class read_context
-{
-public:
-  /// The name of the ELF file from which the CTF archive got
-  /// extracted.
-  string filename;
+class reader;
+
+static typedef_decl_sptr
+process_ctf_typedef(reader *rdr,
+                    corpus_sptr corp,
+                    translation_unit_sptr tunit,
+                    ctf_dict_t *ctf_dictionary,
+                    ctf_id_t ctf_type);
+
+static type_decl_sptr
+process_ctf_base_type(reader *rdr,
+                      corpus_sptr corp,
+                      translation_unit_sptr tunit,
+                      ctf_dict_t *ctf_dictionary,
+                      ctf_id_t ctf_type);
+
+static decl_base_sptr
+build_ir_node_for_variadic_parameter_type(reader &rdr,
+                                          translation_unit_sptr tunit);
+
+static function_type_sptr
+process_ctf_function_type(reader *rdr,
+                          corpus_sptr corp,
+                          translation_unit_sptr tunit,
+                          ctf_dict_t *ctf_dictionary,
+                          ctf_id_t ctf_type);
+
+static void
+process_ctf_sou_members(reader *rdr,
+                        corpus_sptr corp,
+                        translation_unit_sptr tunit,
+                        ctf_dict_t *ctf_dictionary,
+                        ctf_id_t ctf_type,
+                        class_or_union_sptr sou);
+
+static type_base_sptr
+process_ctf_forward_type(reader *rdr,
+                         translation_unit_sptr tunit,
+                         ctf_dict_t *ctf_dictionary,
+                         ctf_id_t ctf_type);
+
+static class_decl_sptr
+process_ctf_struct_type(reader *rdr,
+                        corpus_sptr corp,
+                        translation_unit_sptr tunit,
+                        ctf_dict_t *ctf_dictionary,
+                        ctf_id_t ctf_type);
+
+static union_decl_sptr
+process_ctf_union_type(reader *rdr,
+                       corpus_sptr corp,
+                       translation_unit_sptr tunit,
+                       ctf_dict_t *ctf_dictionary,
+                       ctf_id_t ctf_type);
+
+static array_type_def_sptr
+process_ctf_array_type(reader *rdr,
+                       corpus_sptr corp,
+                       translation_unit_sptr tunit,
+                       ctf_dict_t *ctf_dictionary,
+                       ctf_id_t ctf_type);
+
+static type_base_sptr
+process_ctf_qualified_type(reader *rdr,
+                           corpus_sptr corp,
+                           translation_unit_sptr tunit,
+                           ctf_dict_t *ctf_dictionary,
+                           ctf_id_t ctf_type);
+
+static pointer_type_def_sptr
+process_ctf_pointer_type(reader *rdr,
+                         corpus_sptr corp,
+                         translation_unit_sptr tunit,
+                         ctf_dict_t *ctf_dictionary,
+                         ctf_id_t ctf_type);
+
+static enum_type_decl_sptr
+process_ctf_enum_type(reader *rdr,
+                      translation_unit_sptr tunit,
+                      ctf_dict_t *ctf_dictionary,
+                      ctf_id_t ctf_type);
 
-  /// The IR environment.
-  ir::environment *ir_env;
+static void
+fill_ctf_section(const Elf_Scn *elf_section, ctf_sect_t *ctf_section);
 
+static ctf_id_t
+lookup_symbol_in_ctf_archive(ctf_archive_t *ctfa, ctf_dict_t **ctf_dict,
+                             const char *sym_name);
+
+static std::string
+dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type);
+
+/// The abstraction of a CTF reader.
+///
+/// It groks the type information contains the CTF-specific part of
+/// the ELF file and builds an ABI corpus out of it.
+class reader : public elf_based_reader
+{
   /// The CTF archive read from FILENAME.  If an archive couldn't
   /// be read from the file then this is NULL.
   ctf_archive_t *ctfa;
@@ -67,140 +156,20 @@ public:
   /// A set associating unknown CTF type ids
   std::set<ctf_id_t> unknown_types_set;
 
-  /// libelf handler for the ELF file from which we read the CTF data,
-  /// and the corresponding file descriptor.
-  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;
-
   /// Raw contents of several sections from the ELF file.  These are
   /// used by libctf.
   ctf_sect_t ctf_sect;
   ctf_sect_t symtab_sect;
   ctf_sect_t strtab_sect;
 
-  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.
-  ///
-  /// Note that this @ref read_context is not responsible for the live
-  /// time of the exported_decls_builder object.  The corpus is.
-  ///
-  /// @param b the new builder.
-  void
-  exported_decls_builder(corpus::exported_decls_builder* b)
-  {exported_decls_builder_ = b;}
+public:
 
   /// Getter of the exported decls builder object.
   ///
   /// @return the exported decls builder.
   corpus::exported_decls_builder*
   exported_decls_builder()
-  {return exported_decls_builder_;}
-
-  /// If a given function decl is suitable for the set of exported
-  /// functions of the current corpus, this function adds it to that
-  /// set.
-  ///
-  /// @param fn the function to consider for inclusion into the set of
-  /// exported functions of the current corpus.
-  void
-  maybe_add_fn_to_exported_decls(function_decl* fn)
-  {
-    if (fn)
-      if (corpus::exported_decls_builder* b = exported_decls_builder())
-	b->maybe_add_fn_to_exported_fns(fn);
-  }
-
-  /// If a given variable decl is suitable for the set of exported
-  /// variables of the current corpus, this variable adds it to that
-  /// set.
-  ///
-  /// @param fn the variable to consider for inclusion into the set of
-  /// exported variables of the current corpus.
-  void
-  maybe_add_var_to_exported_decls(var_decl* var)
-  {
-    if (var)
-      if (corpus::exported_decls_builder* b = exported_decls_builder())
-	b->maybe_add_var_to_exported_vars(var);
-  }
-
-  /// Getter of the current corpus group being constructed.
-  ///
-  /// @return current the current corpus being constructed, if any, or
-  /// nil.
-  const corpus_group_sptr
-  current_corpus_group() const
-  {return cur_corpus_group_;}
-
-  /// Test if there is a corpus group being built.
-  ///
-  /// @return if there is a corpus group being built, false otherwise.
-  bool
-  has_corpus_group() const
-  {return bool(cur_corpus_group_);}
-
-  /// Return the main corpus from the current corpus group, if any.
-  ///
-  /// @return the main corpus of the current corpus group, if any, nil
-  /// if no corpus group is being constructed.
-  corpus_sptr
-  main_corpus_from_current_group()
-  {
-    if (cur_corpus_group_)
-      return cur_corpus_group_->get_main_corpus();
-    return corpus_sptr();
-  }
-
-  /// Test if the current corpus being built is the main corpus of the
-  /// current corpus group.
-  ///
-  /// @return return true iff the current corpus being built is the
-  /// main corpus of the current corpus group.
-  bool
-  current_corpus_is_main_corpus_from_current_group()
-  {
-    corpus_sptr main_corpus = main_corpus_from_current_group();
-
-    if (main_corpus && main_corpus.get() == cur_corpus_.get())
-      return true;
-
-    return false;
-  }
-
-  /// Return true if the current corpus is part of a corpus group
-  /// being built and if it's not the main corpus of the group.
-  ///
-  /// For instance, this would return true if we are loading a linux
-  /// kernel *module* that is part of the current corpus group that is
-  /// being built.  In this case, it means we should re-use types
-  /// coming from the "vmlinux" binary that is the main corpus of the
-  /// group.
-  ///
-  /// @return the corpus group the current corpus belongs to, if the
-  /// current corpus is part of a corpus group being built. Nil otherwise.
-  corpus_sptr
-  should_reuse_type_from_corpus_group()
-  {
-    if (has_corpus_group())
-      if (corpus_sptr main_corpus = main_corpus_from_current_group())
-	if (!current_corpus_is_main_corpus_from_current_group())
-	  return current_corpus_group();
-
-    return corpus_sptr();
-  }
+  {return corpus()->get_exported_decls_builder().get();}
 
   /// Associate a given CTF type ID with a given libabigail IR type.
   ///
@@ -269,67 +238,490 @@ public:
   /// 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,
-               const vector<char**>& debug_info_root_paths,
-               ir::environment *env) :
-   ctfa(NULL)
+  reader(const string&		elf_path,
+	 const vector<char**>&	debug_info_root_paths,
+	 environment&		env)
+    : elf_based_reader(elf_path, debug_info_root_paths, env)
   {
-    initialize(elf_path, debug_info_root_paths, env);
+    initialize();
   }
 
-  /// Initializer of read_context.
+  /// Initializer of the reader.
   ///
-  /// @param elf_path the path to the elf file the context is to be
-  /// used for.
+  /// This is useful to clear out the data used by the reader and get
+  /// it ready to be used again.
   ///
-  /// @param debug_info_root_paths vector with the paths
-  /// to directories where .debug file is located.
+  /// Note that the reader eeps the same environment it has been
+  /// originally created with.
   ///
-  /// @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
-  /// that ABI artifacts that are to be compared all need to be
-  /// created within the same environment.
+  /// Please also note that the life time of this environment object
+  /// must be greater than the life time of the resulting @ref
+  /// reader the context uses resources that are allocated in
+  /// the environment.
+  void
+  initialize()
+  {
+    ctfa = nullptr;
+    types_map.clear();
+    corpus_group().reset();
+  }
+
+  /// Initializer of the reader.
+  ///
+  ///
+  /// @param elf_path the new path to the new ELF file to use.
+  ///
+  /// @param debug_info_root_paths a vector of paths to use to look
+  /// for debug info that is split out into a separate file.
+  ///
+  /// This is useful to clear out the data used by the reader and get
+  /// it ready to be used again.
+  ///
+  /// Note that the reader eeps the same environment it has been
+  /// originally created with.
   ///
   /// Please also note that the life time of this environment object
   /// must be greater than the life time of the resulting @ref
-  /// read_context the context uses resources that are allocated in
+  /// reader the context uses resources that are allocated in
   /// the environment.
   void
   initialize(const string& elf_path,
-             const vector<char**>& debug_info_root_paths,
-             ir::environment *env)
+             const vector<char**>& debug_info_root_paths)
   {
-    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;
+    reset(elf_path, debug_info_root_paths);
+  }
+
+  /// Getter of the environment of the current CTF reader.
+  ///
+  /// @return the environment of the current CTF reader.
+  const environment&
+  env() const
+  {return options().env;}
+
+  /// Getter of the environment of the current CTF reader.
+  ///
+  /// @return the environment of the current CTF reader.
+  environment&
+  env()
+  {return options().env;}
+
+  /// Look for vmlinux.ctfa file in default directory or in
+  /// directories provided by debug-info-dir command line option,
+  /// it stores location path in @ref ctfa_file.
+  ///
+  /// @param ctfa_file file name found.
+  /// @return true if file is found.
+  bool
+  find_ctfa_file(std::string& ctfa_file)
+  {
+    std::string ctfa_dirname;
+    dir_name(corpus_path(), ctfa_dirname, false);
+
+    // In corpus group we assume vmlinux as first file to
+    // be processed, so default location for vmlinux.cfa
+    // is vmlinux dirname.
+    ctfa_file = ctfa_dirname + "/vmlinux.ctfa";
+    if (file_exists(ctfa_file))
+      return true;
+
+    // If it's proccessing a module, then location directory
+    // for vmlinux.ctfa should be provided with --debug-info-dir
+    // option.
+    for (const auto& path : debug_info_root_paths())
+      {
+	ctfa_dirname = *path;
+	ctfa_file = ctfa_dirname + "/vmlinux.ctfa";
+	if (file_exists(ctfa_file))
+	  return true;
+      }
+
+    return false;
+  }
+
+  /// Slurp certain information from the underlying ELF file, and
+  /// install it the current libabigail corpus associated to the
+  /// current CTF reader.
+  ///
+  /// @param status the resulting status flags.
+  void
+  slurp_elf_info(fe_iface::status& status)
+  {
+    // Read the ELF-specific parts of the corpus.
+    elf_reader::reader::read_corpus(status);
+
+    if ((status & STATUS_NO_SYMBOLS_FOUND)
+	|| !(status & STATUS_OK))
+      // Either we couldn't find ELF symbols or something went badly
+      // wrong.  There is nothing we can do with this ELF file.  Bail
+      // out.
+      return;
+
+    corpus_sptr corp = corpus();
+    if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
+	&& corpus_group())
+      {
+	status |= fe_iface::STATUS_OK;
+	return;
+      }
+
+    /* Get the raw ELF section contents for libctf.  */
+    if (!find_ctf_section())
+      {
+	status |= fe_iface::STATUS_DEBUG_INFO_NOT_FOUND;
+	return;
+      }
+
+    GElf_Ehdr *ehdr, eh_mem;
+    if (!(ehdr = gelf_getehdr(elf_handle(), &eh_mem)))
+      return;
+
+    // ET_{EXEC,DYN} needs .dyn{sym,str} in ctf_arc_bufopen
+    const char *symtab_name = ".dynsym";
+    const char *strtab_name = ".dynstr";
+
+    if (ehdr->e_type == ET_REL)
+      {
+	symtab_name = ".symtab";
+	strtab_name = ".strtab";
+      }
+
+    const Elf_Scn* ctf_scn = find_ctf_section();
+    fill_ctf_section(ctf_scn, &ctf_sect);
+
+    const Elf_Scn* symtab_scn =
+      elf_helpers::find_section_by_name(elf_handle(), symtab_name);
+    fill_ctf_section(symtab_scn, &symtab_sect);
+
+    const Elf_Scn* strtab_scn =
+      elf_helpers::find_section_by_name(elf_handle(), strtab_name);
+    fill_ctf_section(strtab_scn, &strtab_sect);
+
+    status |= fe_iface::STATUS_OK;
+  }
+
+  /// Process a CTF archive and create libabigail IR for the types,
+  /// variables and function declarations found in the archive, iterating
+  /// over public symbols.  The IR is added to the given corpus.
+  ///
+  /// @param corp the IR corpus to which add the new contents.
+  void
+  process_ctf_archive(corpus_sptr corp)
+  {
+    /* We only have a translation unit.  */
+    translation_unit_sptr ir_translation_unit =
+      std::make_shared<translation_unit>(env(), "", 64);
+    ir_translation_unit->set_language(translation_unit::LANG_C);
+    corp->add(ir_translation_unit);
+
+    int ctf_err;
+    ctf_dict_t *ctf_dict, *dict_tmp;
+    const auto symt = symtab();
+    symtab_reader::symtab_filter filter = symt->make_filter();
+    filter.set_public_symbols();
+    std::string dict_name;
+
+    if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
+	&& corpus_group())
+      {
+	tools_utils::base_name(corpus_path(), dict_name);
+
+	if (dict_name != "vmlinux")
+	  // remove .ko suffix
+	  dict_name.erase(dict_name.length() - 3, 3);
+
+	std::replace(dict_name.begin(), dict_name.end(), '-', '_');
+      }
+
+    if ((ctf_dict = ctf_dict_open(ctfa,
+				  dict_name.empty() ? NULL : dict_name.c_str(),
+				  &ctf_err)) == NULL)
+      {
+	fprintf(stderr, "ERROR dictionary not found\n");
+	abort();
+      }
+
+    dict_tmp = ctf_dict;
+
+    for (const auto& symbol : symtab_reader::filtered_symtab(*symt, filter))
+      {
+	std::string sym_name = symbol->get_name();
+	ctf_id_t ctf_sym_type;
+
+	ctf_sym_type = lookup_symbol_in_ctf_archive(ctfa, &ctf_dict,
+						    sym_name.c_str());
+	if (ctf_sym_type == CTF_ERR)
+          continue;
+
+	if (ctf_type_kind(ctf_dict, ctf_sym_type) != CTF_K_FUNCTION)
+	  {
+	    const char *var_name = sym_name.c_str();
+	    type_base_sptr var_type = lookup_type(corp, ir_translation_unit,
+						  ctf_dict, ctf_sym_type);
+	    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));
+
+	    var_declaration->set_symbol(symbol);
+	    add_decl_to_scope(var_declaration,
+			      ir_translation_unit->get_global_scope());
+	    var_declaration->set_is_in_public_symbol_table(true);
+	    maybe_add_var_to_exported_decls(var_declaration.get());
+	  }
+	else
+	  {
+	    const char *func_name = sym_name.c_str();
+	    ctf_id_t ctf_sym = ctf_sym_type;
+	    type_base_sptr func_type = lookup_type(corp, ir_translation_unit,
+						   ctf_dict, ctf_sym);
+	    if (!func_type)
+	      /* Ignore function if its type can't be sorted out.  */
+	      continue;
+
+	    function_decl_sptr func_declaration;
+	    func_declaration.reset(new function_decl(func_name,
+						     func_type,
+						     0 /* is_inline */,
+						     location()));
+	    func_declaration->set_symbol(symbol);
+	    add_decl_to_scope(func_declaration,
+			      ir_translation_unit->get_global_scope());
+	    func_declaration->set_is_in_public_symbol_table(true);
+	    maybe_add_fn_to_exported_decls(func_declaration.get());
+	  }
+
+	ctf_dict = dict_tmp;
+      }
+
+    ctf_dict_close(ctf_dict);
+    /* 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.  */
+    canonicalize_all_types();
+  }
+
+  /// Add a new type declaration to the given libabigail IR corpus CORP.
+  ///
+  /// @param corp the libabigail IR corpus being constructed.
+  /// @param tunit the current IR translation unit.
+  /// @param ctf_dictionary the CTF dictionary being read.
+  /// @param ctf_type the CTF type ID of the source type.
+  ///
+  /// 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.
+  type_base_sptr
+  process_ctf_type(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;
+
+    if (lookup_unknown_type(ctf_type))
+      return nullptr;
+
+    if ((result = lookup_type(ctf_dictionary, ctf_type)))
+      return result;
+
+    switch (type_kind)
+      {
+      case CTF_K_INTEGER:
+      case CTF_K_FLOAT:
+	{
+	  type_decl_sptr type_decl
+	    = process_ctf_base_type(this, corp, tunit, ctf_dictionary, ctf_type);
+	  result = is_type(type_decl);
+	  break;
+	}
+      case CTF_K_TYPEDEF:
+	{
+	  typedef_decl_sptr typedef_decl
+	    = process_ctf_typedef(this, corp, tunit, ctf_dictionary, ctf_type);
+	  result = is_type(typedef_decl);
+	  break;
+	}
+      case CTF_K_POINTER:
+	{
+	  pointer_type_def_sptr pointer_type
+	    = process_ctf_pointer_type(this, corp, tunit, ctf_dictionary, ctf_type);
+	  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(this, corp, tunit, ctf_dictionary, ctf_type);
+	  result = qualified_type;
+	  break;
+	}
+      case CTF_K_ARRAY:
+	{
+	  array_type_def_sptr array_type
+	    = process_ctf_array_type(this, corp, tunit, ctf_dictionary, ctf_type);
+	  result = array_type;
+	  break;
+	}
+      case CTF_K_ENUM:
+	{
+	  enum_type_decl_sptr enum_type
+	    = process_ctf_enum_type(this, tunit, ctf_dictionary, ctf_type);
+	  result = enum_type;
+	  break;
+	}
+      case CTF_K_FUNCTION:
+	{
+	  function_type_sptr function_type
+	    = process_ctf_function_type(this, corp, tunit, ctf_dictionary, ctf_type);
+	  result = function_type;
+	  break;
+	}
+      case CTF_K_STRUCT:
+	{
+	  class_decl_sptr struct_decl
+	    = process_ctf_struct_type(this, corp, tunit, ctf_dictionary, ctf_type);
+	  result = is_type(struct_decl);
+	  break;
+	}
+      case CTF_K_FORWARD:
+	{
+	  result = process_ctf_forward_type(this, tunit,
+					    ctf_dictionary,
+					    ctf_type);
+	}
+	break;
+      case CTF_K_UNION:
+	{
+	  union_decl_sptr union_decl
+	    = process_ctf_union_type(this, corp, tunit, ctf_dictionary, ctf_type);
+	  result = is_type(union_decl);
+	  break;
+	}
+      case CTF_K_UNKNOWN:
+	/* Unknown types are simply ignored.  */
+      default:
+	break;
+      }
+
+    if (!result)
+      {
+	fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
+	add_unknown_type(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 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.
+  type_base_sptr
+  lookup_type(corpus_sptr corp,
+	      translation_unit_sptr tunit, ctf_dict_t *ctf_dictionary,
+	      ctf_id_t ctf_type)
+  {
+    type_base_sptr result = lookup_type(ctf_dictionary, ctf_type);
+
+    if (!result)
+      result = process_ctf_type(corp, tunit, ctf_dictionary, ctf_type);
+    return result;
+  }
+
+  /// Read the CTF information in the binary and construct an ABI
+  /// corpus from it.
+  ///
+  /// @param status output parameter.  Contains the status of the ABI
+  /// corpus construction.
+  ///
+  /// @return the corpus created as a result of processing the debug
+  /// information.
+  corpus_sptr
+  read_corpus(fe_iface::status &status)
+  {
+    corpus_sptr corp = corpus();
+    status = fe_iface::STATUS_UNKNOWN;
+
+    bool is_linux_kernel = elf_helpers::is_linux_kernel(elf_handle());
+    corpus::origin origin = corpus::CTF_ORIGIN;
+
+    if (is_linux_kernel)
+      origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
+    corp->set_origin(origin);
+
+    if (corpus_group())
+      corpus_group()->add_corpus(corpus());
+
+    slurp_elf_info(status);
+    if (!is_linux_kernel
+	&& ((status & fe_iface::STATUS_DEBUG_INFO_NOT_FOUND) |
+	    (status & fe_iface::STATUS_NO_SYMBOLS_FOUND)))
+      return corp;
+
+    int errp;
+    if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
+	&& corpus_group())
+      {
+	if (ctfa == NULL)
+	  {
+	    std::string ctfa_filename;
+	    if (find_ctfa_file(ctfa_filename))
+	      ctfa = ctf_arc_open(ctfa_filename.c_str(), &errp);
+	  }
+      }
+    else
+      /* Build the ctfa from the contents of the relevant ELF sections,
+	 and 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.  */
+      ctfa = ctf_arc_bufopen(&ctf_sect, &symtab_sect,
+			     &strtab_sect, &errp);
+
+    env().canonicalization_is_done(false);
+    if (ctfa == NULL)
+      status |= fe_iface::STATUS_DEBUG_INFO_NOT_FOUND;
+    else
+      {
+	process_ctf_archive(corp);
+	corpus()->sort_functions();
+	corpus()->sort_variables();
+      }
+
+    env().canonicalization_is_done(true);
+
+    return corp;
   }
 
-  ~read_context()
+  /// Destructor of the CTF reader.
+  ~reader()
   {
     ctf_close(ctfa);
   }
-}; // end class read_context.
+}; // end class reader.
 
-/// 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);
+typedef shared_ptr<reader> reader_sptr;
 
 /// Build and return a typedef libabigail IR.
 ///
-/// @param ctxt the read context.
+/// @param rdr the read context.
 /// @param corp the libabigail IR corpus being constructed.
 /// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
@@ -338,7 +730,7 @@ static type_base_sptr lookup_type(read_context *ctxt,
 /// @return a shared pointer to the IR node for the typedef.
 
 static typedef_decl_sptr
-process_ctf_typedef(read_context *ctxt,
+process_ctf_typedef(reader *rdr,
                     corpus_sptr corp,
                     translation_unit_sptr tunit,
                     ctf_dict_t *ctf_dictionary,
@@ -351,17 +743,17 @@ process_ctf_typedef(read_context *ctxt,
     return result;
 
   const char *typedef_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
-  if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+  if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
     if (result = lookup_typedef_type(typedef_name, *corp))
       return result;
 
-  type_base_sptr utype = lookup_type(ctxt, corp, tunit,
-                                     ctf_dictionary, ctf_utype);
+  type_base_sptr utype = rdr->lookup_type(corp, tunit,
+					  ctf_dictionary, ctf_utype);
 
   if (!utype)
     return result;
 
-  result = dynamic_pointer_cast<typedef_decl>(ctxt->lookup_type(ctf_dictionary,
+  result = dynamic_pointer_cast<typedef_decl>(rdr->lookup_type(ctf_dictionary,
                                                                 ctf_type));
   if (result)
     return result;
@@ -383,7 +775,7 @@ process_ctf_typedef(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_dictionary, ctf_type, result);
+      rdr->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -392,7 +784,7 @@ process_ctf_typedef(read_context *ctxt,
 /// Build and return an integer or float type declaration libabigail
 /// IR.
 ///
-/// @param ctxt the read context.
+/// @param rdr the read context.
 /// @param corp the libabigail IR corpus being constructed.
 /// @param ctf_dictionary the CTF dictionary being read.
 /// @param ctf_type the CTF type ID of the source type.
@@ -400,7 +792,7 @@ process_ctf_typedef(read_context *ctxt,
 /// @return a shared pointer to the IR node for the type.
 
 static type_decl_sptr
-process_ctf_base_type(read_context *ctxt,
+process_ctf_base_type(reader *rdr,
                       corpus_sptr corp,
                       translation_unit_sptr tunit,
                       ctf_dict_t *ctf_dictionary,
@@ -425,14 +817,14 @@ process_ctf_base_type(read_context *ctxt,
       && type_encoding.cte_format == CTF_INT_SIGNED)
     {
       /* This is the `void' type.  */
-      type_base_sptr void_type = ctxt->ir_env->get_void_type();
+      type_base_sptr void_type = rdr->env().get_void_type();
       decl_base_sptr type_declaration = get_type_declaration(void_type);
       result = is_type_decl(type_declaration);
       canonicalize(result);
     }
   else
     {
-      if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+      if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
         {
           string normalized_type_name = type_name;
           integral_type int_type;
@@ -444,7 +836,7 @@ process_ctf_base_type(read_context *ctxt,
 
       result = lookup_basic_type(type_name, *corp);
       if (!result)
-        result.reset(new type_decl(ctxt->ir_env,
+        result.reset(new type_decl(rdr->env(),
                                    type_name,
                                    type_encoding.cte_bits,
                                    type_alignment * 8 /* in bits */,
@@ -456,7 +848,7 @@ process_ctf_base_type(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_dictionary, ctf_type, result);
+      rdr->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -464,17 +856,16 @@ process_ctf_base_type(read_context *ctxt,
 
 /// Build the IR node for a variadic parameter type.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the read context to use.
 ///
 /// @return the variadic parameter type.
 static decl_base_sptr
-build_ir_node_for_variadic_parameter_type(read_context &ctxt,
+build_ir_node_for_variadic_parameter_type(reader &rdr,
                                           translation_unit_sptr tunit)
 {
 
-  ir::environment* env = ctxt.ir_env;
-  ABG_ASSERT(env);
-  type_base_sptr t = env->get_variadic_parameter_type();
+  const ir::environment& env = rdr.env();
+  type_base_sptr t = env.get_variadic_parameter_type();
   decl_base_sptr type_declaration = get_type_declaration(t);
   if (!has_scope(type_declaration))
     add_decl_to_scope(type_declaration, tunit->get_global_scope());
@@ -484,7 +875,7 @@ build_ir_node_for_variadic_parameter_type(read_context &ctxt,
 
 /// Build and return a function type libabigail IR.
 ///
-/// @param ctxt the read context.
+/// @param rdr the read context.
 /// @param corp the libabigail IR corpus being constructed.
 /// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
@@ -493,7 +884,7 @@ build_ir_node_for_variadic_parameter_type(read_context &ctxt,
 /// @return a shared pointer to the IR node for the function type.
 
 static function_type_sptr
-process_ctf_function_type(read_context *ctxt,
+process_ctf_function_type(reader *rdr,
                           corpus_sptr corp,
                           translation_unit_sptr tunit,
                           ctf_dict_t *ctf_dictionary,
@@ -508,8 +899,8 @@ process_ctf_function_type(read_context *ctxt,
 
   /* 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);
+  type_base_sptr ret_type = rdr->lookup_type(corp, tunit,
+					     ctf_dictionary, ctf_ret_type);
   if (!ret_type)
     return result;
 
@@ -524,8 +915,8 @@ process_ctf_function_type(read_context *ctxt,
   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);
+      type_base_sptr arg_type = rdr->lookup_type(corp, tunit,
+						 ctf_dictionary, ctf_arg_type);
       if (!arg_type)
         return result;
 
@@ -540,7 +931,7 @@ process_ctf_function_type(read_context *ctxt,
   if (vararg_p)
     {
       type_base_sptr arg_type =
-       is_type(build_ir_node_for_variadic_parameter_type(*ctxt, tunit));
+       is_type(build_ir_node_for_variadic_parameter_type(*rdr, tunit));
 
       function_decl::parameter_sptr parm
        (new function_decl::parameter(arg_type, "",
@@ -550,7 +941,7 @@ process_ctf_function_type(read_context *ctxt,
       function_parms.push_back(parm);
     }
 
-  result = dynamic_pointer_cast<function_type>(ctxt->lookup_type(ctf_dictionary,
+  result = dynamic_pointer_cast<function_type>(rdr->lookup_type(ctf_dictionary,
                                                                  ctf_type));
   if (result)
     return result;
@@ -567,7 +958,7 @@ process_ctf_function_type(read_context *ctxt,
       result->set_is_artificial(true);
       decl_base_sptr function_type_decl = get_type_declaration(result);
       add_decl_to_scope(function_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_dictionary, ctf_type, result);
+      rdr->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -575,7 +966,7 @@ process_ctf_function_type(read_context *ctxt,
 
 /// Add member information to a IR struct or union type.
 ///
-/// @param ctxt the read context.
+/// @param rdr the read context.
 /// @param corp the libabigail IR corpus being constructed.
 /// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
@@ -583,7 +974,7 @@ process_ctf_function_type(read_context *ctxt,
 /// @param sou the IR struct or union type to which add the members.
 
 static void
-process_ctf_sou_members(read_context *ctxt,
+process_ctf_sou_members(reader *rdr,
                         corpus_sptr corp,
                         translation_unit_sptr tunit,
                         ctf_dict_t *ctf_dictionary,
@@ -609,9 +1000,9 @@ process_ctf_sou_members(read_context *ctxt,
         return;
 
       /* Build the IR for the member's type.  */
-      type_base_sptr member_type = lookup_type(ctxt, corp, tunit,
-                                               ctf_dictionary,
-                                               member_ctf_type);
+      type_base_sptr member_type = rdr->lookup_type(corp, tunit,
+						    ctf_dictionary,
+						    member_ctf_type);
       if (!member_type)
         /* Ignore this member.  */
         continue;
@@ -635,14 +1026,14 @@ process_ctf_sou_members(read_context *ctxt,
 /// Create a declaration-only union or struct type and add it to the
 /// IR.
 ///
-/// @param ctxt the read context.
+/// @param rdr the read context.
 /// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
 /// @param ctf_type the CTF type ID of the source type.
 /// @return the resulting IR node created.
 
 static type_base_sptr
-process_ctf_forward_type(read_context *ctxt,
+process_ctf_forward_type(reader *rdr,
                          translation_unit_sptr tunit,
                          ctf_dict_t *ctf_dictionary,
                          ctf_id_t ctf_type)
@@ -656,24 +1047,24 @@ process_ctf_forward_type(read_context *ctxt,
   if (kind == CTF_K_UNION)
     {
       union_decl_sptr
-       union_fwd(new union_decl(ctxt->ir_env,
-                                type_name,
-                                /*alignment=*/0,
-                                location(),
-                                decl_base::VISIBILITY_DEFAULT,
-                                type_is_anonymous));
+	union_fwd(new union_decl(rdr->env(),
+				 type_name,
+				 /*alignment=*/0,
+				 location(),
+				 decl_base::VISIBILITY_DEFAULT,
+				 type_is_anonymous));
       union_fwd->set_is_declaration_only(true);
       result = union_fwd;
     }
   else
     {
       if (!type_is_anonymous)
-        if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+        if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
           if (result = lookup_class_type(type_name, *corp))
             return is_type(result);
 
       class_decl_sptr
-       struct_fwd(new class_decl(ctxt->ir_env, type_name,
+	struct_fwd(new class_decl(rdr->env(), type_name,
                                  /*alignment=*/0, /*size=*/0,
                                  true /* is_struct */,
                                  location(),
@@ -687,14 +1078,14 @@ process_ctf_forward_type(read_context *ctxt,
     return is_type(result);
 
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_dictionary, ctf_type, is_type(result));
+  rdr->add_type(ctf_dictionary, ctf_type, is_type(result));
 
   return is_type(result);
 }
 
 /// Build and return a struct type libabigail IR.
 ///
-/// @param ctxt the read context.
+/// @param rdr the read context.
 /// @param corp the libabigail IR corpus being constructed.
 /// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
@@ -703,7 +1094,7 @@ process_ctf_forward_type(read_context *ctxt,
 /// @return a shared pointer to the IR node for the struct type.
 
 static class_decl_sptr
-process_ctf_struct_type(read_context *ctxt,
+process_ctf_struct_type(reader *rdr,
                         corpus_sptr corp,
                         translation_unit_sptr tunit,
                         ctf_dict_t *ctf_dictionary,
@@ -715,12 +1106,12 @@ process_ctf_struct_type(read_context *ctxt,
   bool struct_type_is_anonymous = (struct_type_name == "");
 
   if (!struct_type_is_anonymous)
-    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+    if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
       if (result = lookup_class_type(struct_type_name, *corp))
         return result;
 
   /* The libabigail IR encodes C struct types in `class' IR nodes.  */
-  result.reset(new class_decl(ctxt->ir_env,
+  result.reset(new class_decl(rdr->env(),
                               struct_type_name,
                               ctf_type_size(ctf_dictionary, ctf_type) * 8,
                               ctf_type_align(ctf_dictionary, ctf_type) * 8,
@@ -737,12 +1128,12 @@ process_ctf_struct_type(read_context *ctxt,
      at this point even if the members haven't been added to the IR
      node yet.  */
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_dictionary, ctf_type, result);
+  rdr->add_type(ctf_dictionary, 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,
+  process_ctf_sou_members(rdr, corp, tunit, ctf_dictionary, ctf_type,
                           result);
 
   return result;
@@ -750,7 +1141,7 @@ process_ctf_struct_type(read_context *ctxt,
 
 /// Build and return an union type libabigail IR.
 ///
-/// @param ctxt the read context.
+/// @param rdr the read context.
 /// @param corp the libabigail IR corpus being constructed.
 /// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
@@ -759,7 +1150,7 @@ process_ctf_struct_type(read_context *ctxt,
 /// @return a shared pointer to the IR node for the union type.
 
 static union_decl_sptr
-process_ctf_union_type(read_context *ctxt,
+process_ctf_union_type(reader *rdr,
                        corpus_sptr corp,
                        translation_unit_sptr tunit,
                        ctf_dict_t *ctf_dictionary,
@@ -771,12 +1162,12 @@ process_ctf_union_type(read_context *ctxt,
   bool union_type_is_anonymous = (union_type_name == "");
 
   if (!union_type_is_anonymous)
-    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+    if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
       if (result = lookup_union_type(union_type_name, *corp))
         return result;
 
   /* Create the corresponding libabigail union IR node.  */
-  result.reset(new union_decl(ctxt->ir_env,
+  result.reset(new union_decl(rdr->env(),
                                 union_type_name,
                                 ctf_type_size(ctf_dictionary, ctf_type) * 8,
                                 location(),
@@ -791,12 +1182,12 @@ process_ctf_union_type(read_context *ctxt,
      at this point even if the members haven't been added to the IR
      node yet.  */
   add_decl_to_scope(result, tunit->get_global_scope());
-  ctxt->add_type(ctf_dictionary, ctf_type, result);
+  rdr->add_type(ctf_dictionary, 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,
+  process_ctf_sou_members(rdr, corp, tunit, ctf_dictionary, ctf_type,
                           result);
 
   return result;
@@ -804,7 +1195,7 @@ process_ctf_union_type(read_context *ctxt,
 
 /// Build and return an array type libabigail IR.
 ///
-/// @param ctxt the read context.
+/// @param rdr the read context.
 /// @param corp the libabigail IR corpus being constructed.
 /// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
@@ -813,7 +1204,7 @@ process_ctf_union_type(read_context *ctxt,
 /// @return a shared pointer to the IR node for the array type.
 
 static array_type_def_sptr
-process_ctf_array_type(read_context *ctxt,
+process_ctf_array_type(reader *rdr,
                        corpus_sptr corp,
                        translation_unit_sptr tunit,
                        ctf_dict_t *ctf_dictionary,
@@ -834,20 +1225,20 @@ process_ctf_array_type(read_context *ctxt,
   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);
+  type_base_sptr element_type = rdr->lookup_type(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);
+  type_base_sptr index_type = rdr->lookup_type(corp, tunit,
+					       ctf_dictionary,
+					       ctf_index_type);
   if (!index_type)
     return result;
 
-  result = dynamic_pointer_cast<array_type_def>(ctxt->lookup_type(ctf_dictionary,
+  result = dynamic_pointer_cast<array_type_def>(rdr->lookup_type(ctf_dictionary,
                                                                   ctf_type));
   if (result)
     return result;
@@ -866,7 +1257,7 @@ process_ctf_array_type(read_context *ctxt,
   if (upper_bound.get_unsigned_value() == 0)
     is_infinite = true;
 
-  subrange.reset(new array_type_def::subrange_type(ctxt->ir_env,
+  subrange.reset(new array_type_def::subrange_type(rdr->env(),
                                                    "",
                                                    lower_bound,
                                                    upper_bound,
@@ -887,7 +1278,7 @@ process_ctf_array_type(read_context *ctxt,
     {
       decl_base_sptr array_type_decl = get_type_declaration(result);
       add_decl_to_scope(array_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_dictionary, ctf_type, result);
+      rdr->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -895,14 +1286,14 @@ process_ctf_array_type(read_context *ctxt,
 
 /// Build and return a qualified type libabigail IR.
 ///
-/// @param ctxt the read context.
+/// @param rdr the read context.
 /// @param corp the libabigail IR corpus being constructed.
 /// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
 /// @param ctf_type the CTF type ID of the source type.
 
 static type_base_sptr
-process_ctf_qualified_type(read_context *ctxt,
+process_ctf_qualified_type(reader *rdr,
                            corpus_sptr corp,
                            translation_unit_sptr tunit,
                            ctf_dict_t *ctf_dictionary,
@@ -911,12 +1302,12 @@ process_ctf_qualified_type(read_context *ctxt,
   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);
+  type_base_sptr utype = rdr->lookup_type(corp, tunit,
+					  ctf_dictionary, ctf_utype);
   if (!utype)
     return result;
 
-  result = dynamic_pointer_cast<type_base>(ctxt->lookup_type(ctf_dictionary,
+  result = dynamic_pointer_cast<type_base>(rdr->lookup_type(ctf_dictionary,
                                                              ctf_type));
   if (result)
     return result;
@@ -940,7 +1331,7 @@ process_ctf_qualified_type(read_context *ctxt,
     {
       decl_base_sptr qualified_type_decl = get_type_declaration(result);
       add_decl_to_scope(qualified_type_decl, tunit->get_global_scope());
-      ctxt->add_type(ctf_dictionary, ctf_type, result);
+      rdr->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -948,7 +1339,7 @@ process_ctf_qualified_type(read_context *ctxt,
 
 /// Build and return a pointer type libabigail IR.
 ///
-/// @param ctxt the read context.
+/// @param rdr the read context.
 /// @param corp the libabigail IR corpus being constructed.
 /// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
@@ -957,7 +1348,7 @@ process_ctf_qualified_type(read_context *ctxt,
 /// @return a shared pointer to the IR node for the pointer type.
 
 static pointer_type_def_sptr
-process_ctf_pointer_type(read_context *ctxt,
+process_ctf_pointer_type(reader *rdr,
                          corpus_sptr corp,
                          translation_unit_sptr tunit,
                          ctf_dict_t *ctf_dictionary,
@@ -968,13 +1359,13 @@ process_ctf_pointer_type(read_context *ctxt,
   if (ctf_target_type == CTF_ERR)
     return result;
 
-  type_base_sptr target_type = lookup_type(ctxt, corp, tunit,
-                                           ctf_dictionary,
-                                           ctf_target_type);
+  type_base_sptr target_type = rdr->lookup_type(corp, tunit,
+						ctf_dictionary,
+						ctf_target_type);
   if (!target_type)
     return result;
 
-  result = dynamic_pointer_cast<pointer_type_def>(ctxt->lookup_type(ctf_dictionary,
+  result = dynamic_pointer_cast<pointer_type_def>(rdr->lookup_type(ctf_dictionary,
                                                                     ctf_type));
   if (result)
     return result;
@@ -986,7 +1377,7 @@ process_ctf_pointer_type(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_dictionary, ctf_type, result);
+      rdr->add_type(ctf_dictionary, ctf_type, result);
     }
 
   return result;
@@ -994,7 +1385,7 @@ process_ctf_pointer_type(read_context *ctxt,
 
 /// Build and return an enum type libabigail IR.
 ///
-/// @param ctxt the read context.
+/// @param rdr the read context.
 /// @param corp the libabigail IR corpus being constructed.
 /// @param tunit the current IR translation unit.
 /// @param ctf_dictionary the CTF dictionary being read.
@@ -1003,7 +1394,7 @@ process_ctf_pointer_type(read_context *ctxt,
 /// @return a shared pointer to the IR node for the enum type.
 
 static enum_type_decl_sptr
-process_ctf_enum_type(read_context *ctxt,
+process_ctf_enum_type(reader *rdr,
                       translation_unit_sptr tunit,
                       ctf_dict_t *ctf_dictionary,
                       ctf_id_t ctf_type)
@@ -1012,7 +1403,7 @@ process_ctf_enum_type(read_context *ctxt,
   std::string enum_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
 
   if (!enum_name.empty())
-    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
+    if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
       if (result = lookup_enum_type(enum_name, *corp))
         return result;
 
@@ -1022,7 +1413,7 @@ process_ctf_enum_type(read_context *ctxt,
   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.reset(new type_decl(rdr->env(),
                               "",
                               utype_size_in_bits,
                               utype_size_in_bits,
@@ -1041,7 +1432,7 @@ process_ctf_enum_type(read_context *ctxt,
   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));
+    enms.push_back(enum_type_decl::enumerator(ename, evalue));
   if (ctf_errno(ctf_dictionary) != ECTF_NEXT_END)
     {
       fprintf(stderr, "ERROR from ctf_enum_next\n");
@@ -1053,154 +1444,9 @@ process_ctf_enum_type(read_context *ctxt,
   if (result)
     {
       add_decl_to_scope(result, tunit->get_global_scope());
-      ctxt->add_type(ctf_dictionary, ctf_type, result);
-    }
-
-  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;
-
-  if (ctxt->lookup_unknown_type(ctf_type))
-    return nullptr;
-
-  if ((result = ctxt->lookup_type(ctf_dictionary, ctf_type)))
-    return result;
-
-  switch (type_kind)
-    {
-    case CTF_K_INTEGER:
-    case CTF_K_FLOAT:
-      {
-        type_decl_sptr type_decl
-          = process_ctf_base_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
-        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);
-        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);
-        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);
-        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);
-        result = array_type;
-        break;
-      }
-    case CTF_K_ENUM:
-      {
-        enum_type_decl_sptr enum_type
-          = process_ctf_enum_type(ctxt, tunit, ctf_dictionary, ctf_type);
-        result = enum_type;
-        break;
-      }
-    case CTF_K_FUNCTION:
-      {
-        function_type_sptr function_type
-          = process_ctf_function_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
-        result = function_type;
-        break;
-      }
-    case CTF_K_STRUCT:
-      {
-        class_decl_sptr struct_decl
-          = process_ctf_struct_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
-        result = is_type(struct_decl);
-        break;
-      }
-    case CTF_K_FORWARD:
-      {
-        result = process_ctf_forward_type(ctxt, tunit,
-					  ctf_dictionary,
-                                          ctf_type);
-      }
-      break;
-    case CTF_K_UNION:
-      {
-        union_decl_sptr union_decl
-          = process_ctf_union_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
-        result = is_type(union_decl);
-        break;
-      }
-    case CTF_K_UNKNOWN:
-      /* Unknown types are simply ignored.  */
-    default:
-      break;
+      rdr->add_type(ctf_dictionary, ctf_type, result);
     }
 
-  if (!result)
-    {
-      fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
-      ctxt->add_unknown_type(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_dictionary, ctf_type);
-
-  if (!result)
-    result = process_ctf_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
   return result;
 }
 
@@ -1259,162 +1505,6 @@ lookup_symbol_in_ctf_archive(ctf_archive_t *ctfa, ctf_dict_t **ctf_dict,
   return ctf_type;
 }
 
-/// Process a CTF archive and create libabigail IR for the types,
-/// variables and function declarations found in the archive, iterating
-/// over public symbols.  The IR is added to the given corpus.
-///
-/// @param 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);
-
-  int ctf_err;
-  ctf_dict_t *ctf_dict, *dict_tmp;
-  const auto symtab = ctxt->symtab;
-  symtab_reader::symtab_filter filter = symtab->make_filter();
-  filter.set_public_symbols();
-  std::string dict_name;
-
-  if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
-      && ctxt->cur_corpus_group_)
-    {
-      tools_utils::base_name(ctxt->filename, dict_name);
-
-      if (dict_name != "vmlinux")
-        // remove .ko suffix
-        dict_name.erase(dict_name.length() - 3, 3);
-
-      std::replace(dict_name.begin(), dict_name.end(), '-', '_');
-    }
-
-  if ((ctf_dict = ctf_dict_open(ctxt->ctfa,
-                                dict_name.empty() ? NULL : dict_name.c_str(),
-                                &ctf_err)) == NULL)
-    {
-      fprintf(stderr, "ERROR dictionary not found\n");
-      abort();
-    }
-
-  dict_tmp = ctf_dict;
-
-  for (const auto& symbol : symtab_reader::filtered_symtab(*symtab, filter))
-    {
-      std::string sym_name = symbol->get_name();
-      ctf_id_t ctf_sym_type;
-
-      ctf_sym_type = lookup_symbol_in_ctf_archive(ctxt->ctfa, &ctf_dict,
-                                                  sym_name.c_str());
-      if (ctf_sym_type == CTF_ERR)
-          continue;
-
-      if (ctf_type_kind(ctf_dict, ctf_sym_type) != CTF_K_FUNCTION)
-        {
-          const char *var_name = sym_name.c_str();
-          type_base_sptr var_type = lookup_type(ctxt, corp, ir_translation_unit,
-                                                ctf_dict, ctf_sym_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));
-
-          var_declaration->set_symbol(symbol);
-          add_decl_to_scope(var_declaration,
-                            ir_translation_unit->get_global_scope());
-          var_declaration->set_is_in_public_symbol_table(true);
-          ctxt->maybe_add_var_to_exported_decls(var_declaration.get());
-        }
-      else
-        {
-          const char *func_name = sym_name.c_str();
-          ctf_id_t ctf_sym = ctf_sym_type;
-          type_base_sptr func_type = lookup_type(ctxt, corp, ir_translation_unit,
-                                                 ctf_dict, ctf_sym);
-          if (!func_type)
-            /* Ignore function if its type can't be sorted out.  */
-            continue;
-
-          function_decl_sptr func_declaration;
-          func_declaration.reset(new function_decl(func_name,
-                                                   func_type,
-                                                   0 /* is_inline */,
-                                                   location()));
-          func_declaration->set_symbol(symbol);
-          add_decl_to_scope(func_declaration,
-                            ir_translation_unit->get_global_scope());
-          func_declaration->set_is_in_public_symbol_table(true);
-          ctxt->maybe_add_fn_to_exported_decls(func_declaration.get());
-        }
-
-      ctf_dict = dict_tmp;
-    }
-
-  ctf_dict_close(ctf_dict);
-  /* 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();
-}
-
-/// Open the ELF file described by the given read context.
-///
-/// @param ctxt the read context.
-/// @return 0 if the ELF file can't be opened.
-/// @return 1 otherwise.
-
-static int
-open_elf_handler(read_context *ctxt)
-{
-  /* libelf requires to negotiate/set the version of ELF.  */
-  if (elf_version(EV_CURRENT) == EV_NONE)
-    return 0;
-
-  /* Open an ELF handler.  */
-  ctxt->elf_fd = open(ctxt->filename.c_str(), O_RDONLY);
-  if (ctxt->elf_fd == -1)
-    return 0;
-
-  ctxt->elf_handler = elf_begin(ctxt->elf_fd, ELF_C_READ, NULL);
-  if (ctxt->elf_handler == NULL)
-    {
-      fprintf(stderr, "cannot open %s: %s\n",
-               ctxt->filename.c_str(), elf_errmsg(elf_errno()));
-      close(ctxt->elf_fd);
-      return 0;
-    }
-
-  return 1;
-}
-
-/// Close the ELF file described by the given read context.
-///
-/// @param ctxt the read context.
-
-static void
-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
 /// section.
 ///
@@ -1422,13 +1512,14 @@ close_elf_handler (read_context *ctxt)
 /// @param ctf_section the CTF section to fill with the raw data.
 
 static void
-fill_ctf_section(Elf_Scn *elf_section, ctf_sect_t *ctf_section)
+fill_ctf_section(const Elf_Scn *elf_section, ctf_sect_t *ctf_section)
 {
   GElf_Shdr section_header_mem, *section_header;
   Elf_Data *section_data;
 
-  section_header = gelf_getshdr(elf_section, &section_header_mem);
-  section_data = elf_getdata(elf_section, 0);
+  section_header = gelf_getshdr(const_cast<Elf_Scn*>(elf_section),
+				&section_header_mem);
+  section_data = elf_getdata(const_cast<Elf_Scn*>(elf_section), 0);
 
   ABG_ASSERT (section_header != NULL);
   ABG_ASSERT (section_data != NULL);
@@ -1439,326 +1530,27 @@ 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.
-/// @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, *ctf_dbg_scn;
-  Elf_Scn *strtab_scn;
-
-  if (!(ehdr = gelf_getehdr(ctxt->elf_handler, &eh_mem)))
-      return;
-
-  corp->set_architecture_name(elf_helpers::e_machine_to_string(ehdr->e_machine));
-
-  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)
-      && ctxt->cur_corpus_group_)
-    {
-      status |= elf_reader::STATUS_OK;
-      return;
-    }
-
-  /* Get the raw ELF section contents for libctf.  */
-  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";
-  const char *strtab_name = ".dynstr";
-
-  if (ehdr->e_type == ET_REL)
-    {
-      symtab_name = ".symtab";
-      strtab_name = ".strtab";
-    }
-
-  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 (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);
-
-  status |= elf_reader::STATUS_OK;
-}
-
-/// Looks for vmlinux.ctfa file in default directory or in
-/// directories provided by debug-info-dir command line option,
-/// it stores location path in @ref ctfa_file.
-///
-/// @param ctxt the read context.
-/// @param ctfa_file file name found.
-/// @return true if file is found.
-static bool
-find_ctfa_file(read_context *ctxt, std::string& ctfa_file)
-{
-  std::string ctfa_dirname;
-  dir_name(ctxt->filename, ctfa_dirname, false);
-
-  // In corpus group we assume vmlinux as first file to
-  // be processed, so default location for vmlinux.cfa
-  // is vmlinux dirname.
-  ctfa_file = ctfa_dirname + "/vmlinux.ctfa";
-  if (file_exists(ctfa_file))
-    return true;
-
-  // If it's proccessing a module, then location directory
-  // for vmlinux.ctfa should be provided with --debug-info-dir
-  // option.
-  for (vector<char**>::const_iterator i = ctxt->debug_info_root_paths_.begin();
-       i != ctxt->debug_info_root_paths_.end();
-       ++i)
-    {
-      ctfa_dirname = **i;
-      ctfa_file = ctfa_dirname + "/vmlinux.ctfa";
-      if (file_exists(ctfa_file))
-        return true;
-    }
-
-  return false;
-}
-
 /// 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_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,
-                                            debug_info_root_paths,
-                                            env));
-  return result;
-}
-
-/// 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.
-///
-/// @param status the resulting status of the corpus read.
-///
-/// @return a shared pointer to the read corpus.
-
-corpus_sptr
-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;
-  status = elf_reader::STATUS_UNKNOWN;
-
-  /* Open the ELF file.  */
-  if (!open_elf_handler(ctxt))
-      return corp;
-
-  bool is_linux_kernel = elf_helpers::is_linux_kernel(ctxt->elf_handler);
-  corpus::origin origin = corpus::CTF_ORIGIN;
-
-  if (is_linux_kernel)
-    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
-  corp->set_origin(origin);
-
-  if (ctxt->cur_corpus_group_)
-    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
-
-  slurp_elf_info(ctxt, corp, status);
-  if (!is_linux_kernel
-      && ((status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND) |
-          (status & elf_reader::STATUS_NO_SYMBOLS_FOUND)))
-      return corp;
-
-  // Set the set of exported declaration that are defined.
-  ctxt->exported_decls_builder
-   (ctxt->cur_corpus_->get_exported_decls_builder().get());
-
-  int errp;
-  if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
-      && ctxt->cur_corpus_group_)
-    {
-      if (ctxt->ctfa == NULL)
-        {
-          std::string ctfa_filename;
-          if (find_ctfa_file(ctxt, ctfa_filename))
-            ctxt->ctfa = ctf_arc_open(ctfa_filename.c_str(), &errp);
-        }
-    }
-  else
-    /* Build the ctfa from the contents of the relevant ELF sections,
-       and 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.  */
-    ctxt->ctfa = ctf_arc_bufopen(&ctxt->ctf_sect, &ctxt->symtab_sect,
-                                 &ctxt->strtab_sect, &errp);
-
-  ctxt->ir_env->canonicalization_is_done(false);
-  if (ctxt->ctfa == NULL)
-    status |= elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
-  else
-    {
-      process_ctf_archive(ctxt, corp);
-      ctxt->cur_corpus_->sort_functions();
-      ctxt->cur_corpus_->sort_variables();
-    }
-
-  ctxt->ir_env->canonicalization_is_done(true);
-
-  /* Cleanup and return.  */
-  close_elf_handler(ctxt);
-  return corp;
-}
-
-/// 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.
-///
-/// @param status the resulting status of the corpus read.
-///
-/// @return a shared pointer to the read corpus.
-
-corpus_sptr
-read_corpus(const read_context_sptr &ctxt, elf_reader::status &status)
-{return read_corpus(ctxt.get(), status);}
-
-/// Set the @ref corpus_group being created to the current read context.
-///
-/// @param ctxt the read_context to consider.
-///
-/// @param group the @ref corpus_group to set.
-void
-set_read_context_corpus_group(read_context& ctxt,
-                              corpus_group_sptr& group)
-{
-  ctxt.cur_corpus_group_ = group;
-}
-
-/// Read a corpus and add it to a given @ref corpus_group.
-///
-/// @param ctxt the reading context to consider.
-///
-/// @param group the @ref corpus_group to add the new corpus to.
-///
-/// @param status output parameter. The status of the read.  It is set
-/// by this function upon its completion.
-corpus_sptr
-read_and_add_corpus_to_group_from_elf(read_context* ctxt,
-                                      corpus_group& group,
-                                      elf_reader::status& status)
+elf_based_reader_sptr
+create_ctf_reader(const std::string& elf_path,
+		  const vector<char**>& debug_info_root_paths,
+		  environment& env)
 {
-  corpus_sptr result;
-  corpus_sptr corp = read_corpus(ctxt, status);
-  if (status & elf_reader::STATUS_OK)
-    {
-      if (!corp->get_group())
-        group.add_corpus(corp);
-      result = corp;
-    }
-
+  reader_sptr result(new reader(elf_path,
+				debug_info_root_paths,
+				env));
   return result;
 }
 
-/// Re-initialize a read_context so that it can re-used to read
+/// Re-initialize a reader so that it can re-used to read
 /// another binary.
 ///
-/// @param ctxt the context to re-initialize.
+/// @param rdr the context to re-initialize.
 ///
 /// @param elf_path the path to the elf file the context is to be used
 /// for.
@@ -1771,16 +1563,15 @@ read_and_add_corpus_to_group_from_elf(read_context* ctxt,
 ///
 /// Please also note that the life time of this environment object
 /// must be greater than the life time of the resulting @ref
-/// read_context the context uses resources that are allocated in the
+/// reader the context uses resources that are allocated in the
 /// environment.
 void
-reset_read_context(read_context_sptr	&ctxt,
-                   const std::string&	 elf_path,
-                   const vector<char**>& debug_info_root_path,
-                   ir::environment*	 environment)
+reset_reader(elf_based_reader&		rdr,
+	     const std::string&	elf_path,
+	     const vector<char**>&	debug_info_root_path)
 {
-  if (ctxt)
-    ctxt->initialize(elf_path, debug_info_root_path, environment);
+  ctf_reader::reader& r = dynamic_cast<reader&>(rdr);
+  r.initialize(elf_path, debug_info_root_path);
 }
 
 /// Returns a key to be use in types_map dict conformed by
@@ -1796,7 +1587,7 @@ reset_read_context(read_context_sptr	&ctxt,
 /// was found.
 ///
 /// @param type the id for given CTF type.
-std::string
+static std::string
 dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type)
 {
   std::stringstream key;
diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index ddd040e1..70c85161 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -11,7 +11,7 @@
 /// de-serialize an instance of @ref abigail::corpus from a file in
 /// elf format, containing dwarf information.
 
-#include "config.h"
+#include "abg-internal.h"
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -37,16 +37,16 @@
 #include "abg-ir-priv.h"
 #include "abg-suppression-priv.h"
 #include "abg-corpus-priv.h"
-#include "abg-elf-helpers.h"
-#include "abg-internal.h"
+#include "abg-symtab-reader.h"
 
 // <headers defining libabigail's API go under here>
 ABG_BEGIN_EXPORT_DECLARATIONS
 
 #include "abg-dwarf-reader.h"
+#include "abg-elf-based-reader.h"
 #include "abg-sptr-utils.h"
-#include "abg-symtab-reader.h"
 #include "abg-tools-utils.h"
+#include "abg-elf-helpers.h"
 
 ABG_END_EXPORT_DECLARATIONS
 // </headers defining libabigail's API>
@@ -91,16 +91,6 @@ enum die_source
 				// enumerator
 };
 
-/// A functor used by @ref dwfl_sptr.
-struct dwfl_deleter
-{
-  void
-  operator()(Dwfl* dwfl)
-  {dwfl_end(dwfl);}
-};//end struct dwfl_deleter
-
-/// A convenience typedef for a shared pointer to a Dwfl.
-typedef shared_ptr<Dwfl> dwfl_sptr;
 
 /// A convenience typedef for a vector of Dwarf_Off.
 typedef vector<Dwarf_Off> dwarf_offsets_type;
@@ -143,13 +133,6 @@ typedef unordered_map<interned_string,
 		      hash_interned_string>
 istring_dwarf_offsets_map_type;
 
-/// Convenience typedef for a map which key is an elf address and
-/// which value is an elf_symbol_sptr.
-typedef unordered_map<GElf_Addr, elf_symbol_sptr> addr_elf_symbol_sptr_map_type;
-
-/// Convenience typedef for a set of ELF addresses.
-typedef unordered_set<GElf_Addr> address_set_type;
-
 /// A hasher for a pair of Dwarf_Off.  This is used as a hasher for
 /// the type @ref dwarf_offset_pair_set_type.
 struct dwarf_offset_pair_hash
@@ -244,21 +227,23 @@ typedef unordered_map<std::pair<offset_type, offset_type>,
 /// A convenience typedef for a vector of pairs of offset_type.
 typedef vector<std::pair<offset_type, offset_type>> offset_pair_vector_type;
 
-class read_context;
+class reader;
+
+static translation_unit_sptr
+build_translation_unit_and_add_to_ir(reader&	rdr,
+				     Dwarf_Die*	die,
+				     char		address_size);
 
 static void
-maybe_propagate_canonical_type(const read_context& ctxt,
+maybe_propagate_canonical_type(const reader& rdr,
 			       const Dwarf_Die* l,
 			       const Dwarf_Die* r);
 
 static void
-propagate_canonical_type(const read_context& ctxt,
+propagate_canonical_type(const reader& rdr,
 			 const Dwarf_Die* l,
 			 const Dwarf_Die* r);
 
-/// Convenience typedef for a shared pointer to an @ref address_set_type.
-typedef shared_ptr<address_set_type> address_set_sptr;
-
 /// Convenience typedef for a shared pointer to an
 /// addr_elf_symbol_sptr_map_type.
 typedef shared_ptr<addr_elf_symbol_sptr_map_type> addr_elf_symbol_sptr_map_sptr;
@@ -379,13 +364,13 @@ operator<(const imported_unit_point& l, const imported_unit_point& r)
 {return l.offset_of_import < r.offset_of_import;}
 
 static bool
-get_parent_die(const read_context&	ctxt,
+get_parent_die(const reader&	rdr,
 	       const Dwarf_Die*	die,
 	       Dwarf_Die&		parent_die,
 	       size_t			where_offset);
 
 static bool
-get_scope_die(const read_context&	ctxt,
+get_scope_die(const reader&	rdr,
 	      const Dwarf_Die*		die,
 	      size_t			where_offset,
 	      Dwarf_Die&		scope_die);
@@ -468,7 +453,7 @@ static bool
 is_type_die_to_be_canonicalized(const Dwarf_Die *die);
 
 static bool
-die_is_at_class_scope(const read_context& ctxt,
+die_is_at_class_scope(const reader& rdr,
 		      const Dwarf_Die* die,
 		      size_t where_offset,
 		      Dwarf_Die& class_scope_die);
@@ -510,7 +495,7 @@ static string
 die_name(const Dwarf_Die* die);
 
 static location
-die_location(const read_context& ctxt, const Dwarf_Die* die);
+die_location(const reader& rdr, const Dwarf_Die* die);
 
 static bool
 die_location_address(Dwarf_Die*	die,
@@ -540,27 +525,27 @@ build_internal_underlying_enum_type_name(const string &base_name,
 					 uint64_t size);
 
 static string
-die_qualified_type_name(const read_context& ctxt,
+die_qualified_type_name(const reader& rdr,
 			const Dwarf_Die* die,
 			size_t where);
 
 static string
-die_qualified_decl_name(const read_context& ctxt,
+die_qualified_decl_name(const reader& rdr,
 			const Dwarf_Die* die,
 			size_t where);
 
 static string
-die_qualified_name(const read_context& ctxt,
+die_qualified_name(const reader& rdr,
 		   const Dwarf_Die* die,
 		   size_t where);
 
 static bool
-die_qualified_type_name_empty(const read_context& ctxt,
+die_qualified_type_name_empty(const reader& rdr,
 			      const Dwarf_Die* die, size_t where,
 			      string &qualified_name);
 
 static void
-die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
+die_return_and_parm_names_from_fn_type_die(const reader& rdr,
 					   const Dwarf_Die* die,
 					   size_t where_offset,
 					   bool pretty_print,
@@ -571,7 +556,7 @@ die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
 					   bool& is_static);
 
 static string
-die_function_signature(const read_context& ctxt,
+die_function_signature(const reader& rdr,
 		       const Dwarf_Die *die,
 		       size_t where_offset);
 
@@ -579,7 +564,7 @@ static bool
 die_peel_qual_ptr(Dwarf_Die *die, Dwarf_Die& peeled_die);
 
 static bool
-die_function_type_is_method_type(const read_context& ctxt,
+die_function_type_is_method_type(const reader& rdr,
 				 const Dwarf_Die *die,
 				 size_t where_offset,
 				 Dwarf_Die& object_pointer_die,
@@ -587,23 +572,23 @@ die_function_type_is_method_type(const read_context& ctxt,
 				 bool& is_static);
 
 static string
-die_pretty_print_type(read_context& ctxt,
+die_pretty_print_type(reader& rdr,
 		      const Dwarf_Die* die,
 		      size_t where_offset);
 
 static string
-die_pretty_print_decl(read_context& ctxt,
+die_pretty_print_decl(reader& rdr,
 		      const Dwarf_Die* die,
 		      size_t where_offset);
 
 static string
-die_pretty_print(read_context& ctxt,
+die_pretty_print(reader& rdr,
 		 const Dwarf_Die* die,
 		 size_t where_offset);
 
 static void
 maybe_canonicalize_type(const type_base_sptr&	t,
-			read_context&		ctxt);
+			reader&		rdr);
 
 static uint64_t
 get_default_array_lower_bound(translation_unit::language l);
@@ -614,234 +599,31 @@ find_lower_bound_in_imported_unit_points(const imported_unit_points_type&,
 					 imported_unit_points_type::const_iterator&);
 
 static array_type_def::subrange_sptr
-build_subrange_type(read_context&	ctxt,
+build_subrange_type(reader&	rdr,
 		    const Dwarf_Die*	die,
 		    size_t		where_offset,
 		    bool		associate_type_to_die = true);
 
 static void
-build_subranges_from_array_type_die(read_context&			ctxt,
+build_subranges_from_array_type_die(reader&			rdr,
 				    const Dwarf_Die*			die,
 				    array_type_def::subranges_type&	subranges,
 				    size_t				where_offset,
 				    bool				associate_type_to_die = true);
 
 static comparison_result
-compare_dies(const read_context& ctxt,
+compare_dies(const reader& rdr,
 	     const Dwarf_Die *l, const Dwarf_Die *r,
 	     bool update_canonical_dies_on_the_fly);
 
 static bool
-compare_dies_during_canonicalization(read_context& ctxt,
+compare_dies_during_canonicalization(reader& rdr,
 				     const Dwarf_Die *l, const Dwarf_Die *r,
 				     bool update_canonical_dies_on_the_fly);
 
-
 static bool
 get_member_child_die(const Dwarf_Die *die, Dwarf_Die *child);
 
-/// Find the file name of the alternate debug info file.
-///
-/// @param elf_module the elf module to consider.
-///
-/// @param out parameter.  Is set to the file name of the alternate
-/// debug info file, iff this function returns true.
-///
-/// @return true iff the location of the alternate debug info file was
-/// found.
-static bool
-find_alt_debug_info_link(Dwfl_Module *elf_module,
-			 string &alt_file_name)
-{
-  GElf_Addr bias = 0;
-  Dwarf *dwarf = dwfl_module_getdwarf(elf_module, &bias);
-  Elf *elf = dwarf_getelf(dwarf);
-  GElf_Ehdr ehmem, *elf_header;
-  elf_header = gelf_getehdr(elf, &ehmem);
-
-  Elf_Scn* section = 0;
-  while ((section = elf_nextscn(elf, section)) != 0)
-    {
-      GElf_Shdr header_mem, *header;
-      header = gelf_getshdr(section, &header_mem);
-      if (header->sh_type != SHT_PROGBITS)
-	continue;
-
-      const char *section_name = elf_strptr(elf,
-					    elf_header->e_shstrndx,
-					    header->sh_name);
-
-      char *alt_name = 0;
-      char *buildid = 0;
-      size_t buildid_len = 0;
-      if (section_name != 0
-	  && strcmp(section_name, ".gnu_debugaltlink") == 0)
-	{
-	  Elf_Data *data = elf_getdata(section, 0);
-	  if (data != 0 && data->d_size != 0)
-	    {
-	      alt_name = (char*) data->d_buf;
-	      char *end_of_alt_name =
-		(char *) memchr(alt_name, '\0', data->d_size);
-	      buildid_len = data->d_size - (end_of_alt_name - alt_name + 1);
-	      if (buildid_len == 0)
-		return false;
-	      buildid = end_of_alt_name + 1;
-	    }
-	}
-      else
-	continue;
-
-      if (buildid == 0 || alt_name == 0)
-	return false;
-
-      alt_file_name = alt_name;
-      return true;
-    }
-
-  return false;
-}
-
-/// Find alternate debuginfo file of a given "link" under a set of
-/// root directories.
-///
-/// The link is a string that is read by the function
-/// find_alt_debug_info_link().  That link is a path that is relative
-/// to a given debug info file, e.g, "../../../.dwz/something.debug".
-/// It designates the alternate debug info file associated to a given
-/// debug info file.
-///
-/// This function will thus try to find the .dwz/something.debug file
-/// under some given root directories.
-///
-/// @param root_dirs the set of root directories to look from.
-///
-/// @param alt_file_name a relative path to the alternate debug info
-/// file to look for.
-///
-/// @param alt_file_path the resulting absolute path to the alternate
-/// debuginfo path denoted by @p alt_file_name and found under one of
-/// the directories in @p root_dirs.  This is set iff the function
-/// returns true.
-///
-/// @return true iff the function found the alternate debuginfo file.
-static bool
-find_alt_debug_info_path(const vector<char**> root_dirs,
-			 const string &alt_file_name,
-			 string &alt_file_path)
-{
-  if (alt_file_name.empty())
-    return false;
-
-  string altfile_name = tools_utils::trim_leading_string(alt_file_name, "../");
-
-  for (vector<char**>::const_iterator i = root_dirs.begin();
-       i != root_dirs.end();
-       ++i)
-    if (tools_utils::find_file_under_dir(**i, altfile_name, alt_file_path))
-      return true;
-
-  return false;
-}
-
-/// Return the alternate debug info associated to a given main debug
-/// info file.
-///
-/// @param elf_module the elf module to consider.
-///
-/// @param debug_root_dirs a set of root debuginfo directories under
-/// which too look for the alternate debuginfo file.
-///
-/// @param alt_file_name output parameter.  This is set to the file
-/// path of the alternate debug info file associated to @p elf_module.
-/// This is set iff the function returns a non-null result.
-///
-/// @param alt_fd the file descriptor used to access the alternate
-/// debug info.  If this parameter is set by the function, then the
-/// caller needs to fclose it, otherwise the file descriptor is going
-/// to be leaked.  Note however that on recent versions of elfutils
-/// where libdw.h contains the function dwarf_getalt(), this parameter
-/// is set to 0, so it doesn't need to be fclosed.
-///
-/// Note that the alternate debug info file is a DWARF extension as of
-/// DWARF 4 ans is decribed at
-/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
-///
-/// @return the alternate debuginfo, or null.  If @p alt_fd is
-/// non-zero, then the caller of this function needs to call
-/// dwarf_end() on the returned alternate debuginfo pointer,
-/// otherwise, it's going to be leaked.
-static Dwarf*
-find_alt_debug_info(Dwfl_Module *elf_module,
-		    const vector<char**> debug_root_dirs,
-		    string& alt_file_name,
-		    int& alt_fd)
-{
-  if (elf_module == 0)
-    return 0;
-
-  Dwarf* result = 0;
-  find_alt_debug_info_link(elf_module, alt_file_name);
-
-#ifdef LIBDW_HAS_DWARF_GETALT
-  // We are on recent versions of elfutils where the function
-  // dwarf_getalt exists, so let's use it.
-  Dwarf_Addr bias = 0;
-  Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
-  result = dwarf_getalt(dwarf);
-  alt_fd = 0;
-#else
-  // We are on an old version of elfutils where the function
-  // dwarf_getalt doesn't exist yet, so let's open code its
-  // functionality
-  char *alt_name = 0;
-  const char *file_name = 0;
-  void **user_data = 0;
-  Dwarf_Addr low_addr = 0;
-  char *alt_file = 0;
-
-  file_name = dwfl_module_info(elf_module, &user_data,
-			       &low_addr, 0, 0, 0, 0, 0);
-
-  alt_fd = dwfl_standard_find_debuginfo(elf_module, user_data,
-					file_name, low_addr,
-					alt_name, file_name,
-					0, &alt_file);
-
-  result = dwarf_begin(alt_fd, DWARF_C_READ);
-#endif
-
-  if (result == 0)
-    {
-      // So we didn't find the alternate debuginfo file from the
-      // information that is in the debuginfo file associated to
-      // elf_module.  Maybe the alternate debuginfo file is located
-      // under one of the directories in debug_root_dirs.  So let's
-      // look in there.
-      string alt_file_path;
-      if (!find_alt_debug_info_path(debug_root_dirs,
-				    alt_file_name,
-				    alt_file_path))
-	return result;
-
-      // If we reach this point it means we have found the path to the
-      // alternate debuginfo file and it's in alt_file_path.  So let's
-      // open it and read it.
-      int fd = open(alt_file_path.c_str(), O_RDONLY);
-      if (fd == -1)
-	return result;
-      result = dwarf_begin(fd, DWARF_C_READ);
-
-#ifdef LIBDW_HAS_DWARF_GETALT
-      Dwarf_Addr bias = 0;
-      Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
-      dwarf_setalt(dwarf, result);
-#endif
-    }
-
-  return result;
-}
-
 /// Compare a symbol name against another name, possibly demangling
 /// the symbol_name before performing the comparison.
 ///
@@ -892,7 +674,7 @@ compare_symbol_name(const string& symbol_name,
 /// @param syms_found a vector of symbols found with the name @p
 /// sym_name.  table.
 static bool
-lookup_symbol_from_sysv_hash_tab(const environment*		env,
+lookup_symbol_from_sysv_hash_tab(const environment&		env,
 				 Elf*				elf_handle,
 				 const string&			sym_name,
 				 size_t			ht_index,
@@ -1169,7 +951,7 @@ setup_gnu_ht(Elf* elf_handle,
 ///
 /// @return true if a symbol was actually found.
 static bool
-lookup_symbol_from_gnu_hash_tab(const environment*		env,
+lookup_symbol_from_gnu_hash_tab(const environment&		env,
 				Elf*				elf_handle,
 				const string&			sym_name,
 				size_t				ht_index,
@@ -1301,7 +1083,7 @@ lookup_symbol_from_gnu_hash_tab(const environment*		env,
 /// @return true iff the function found the symbol from the elf hash
 /// table.
 static bool
-lookup_symbol_from_elf_hash_tab(const environment*		env,
+lookup_symbol_from_elf_hash_tab(const environment&		env,
 				Elf*				elf_handle,
 				hash_table_kind		ht_kind,
 				size_t				ht_index,
@@ -1358,7 +1140,7 @@ lookup_symbol_from_elf_hash_tab(const environment*		env,
 ///
 /// @return true iff the symbol was found.
 static bool
-lookup_symbol_from_symtab(const environment*		env,
+lookup_symbol_from_symtab(environment&			env,
 			  Elf*				elf_handle,
 			  const string&		sym_name,
 			  size_t			sym_tab_index,
@@ -1449,7 +1231,7 @@ lookup_symbol_from_symtab(const environment*		env,
 ///
 /// @return true iff a symbol with the name @p symbol_name was found.
 static bool
-lookup_symbol_from_elf(const environment*		env,
+lookup_symbol_from_elf(environment&			env,
 		       Elf*				elf_handle,
 		       const string&			symbol_name,
 		       bool				demangle,
@@ -1500,7 +1282,7 @@ lookup_symbol_from_elf(const environment*		env,
 ///
 /// @return true iff the symbol was found.
 static bool
-lookup_public_function_symbol_from_elf(const environment*		env,
+lookup_public_function_symbol_from_elf(environment&			env,
 				       Elf*				elf_handle,
 				       const string&			symbol_name,
 				       vector<elf_symbol_sptr>&	func_syms)
@@ -1533,120 +1315,6 @@ lookup_public_function_symbol_from_elf(const environment*		env,
   return found;
 }
 
-/// Get data tag information of an ELF file by looking up into its
-/// dynamic segment
-///
-/// @param elf the elf handle to use for the query.
-///
-/// @param dt_tag data tag to look for in dynamic segment
-/// @param dt_tag_data vector of found information for a given @p data_tag
-///
-/// @return true iff data tag @p data_tag was found
-
-bool
-lookup_data_tag_from_dynamic_segment(Elf*                       elf,
-                                     Elf64_Sxword               data_tag,
-                                     vector<string>&            dt_tag_data)
-{
-  size_t num_prog_headers = 0;
-  bool found = false;
-  if (elf_getphdrnum(elf, &num_prog_headers) < 0)
-    return found;
-
-  // Cycle through each program header.
-  for (size_t i = 0; i < num_prog_headers; ++i)
-    {
-      GElf_Phdr phdr_mem;
-      GElf_Phdr *phdr = gelf_getphdr(elf, i, &phdr_mem);
-      if (phdr == NULL || phdr->p_type != PT_DYNAMIC)
-        continue;
-
-      // Poke at the dynamic segment like a section, so that we can
-      // get its section header information; also we'd like to read
-      // the data of the segment by using elf_getdata() but that
-      // function needs a Elf_Scn data structure to act on.
-      // Elfutils doesn't really have any particular function to
-      // access segment data, other than the functions used to
-      // access section data.
-      Elf_Scn *dynamic_section = gelf_offscn(elf, phdr->p_offset);
-      GElf_Shdr  shdr_mem;
-      GElf_Shdr *dynamic_section_header = gelf_getshdr(dynamic_section,
-						       &shdr_mem);
-      if (dynamic_section_header == NULL
-          || dynamic_section_header->sh_type != SHT_DYNAMIC)
-        continue;
-
-      // Get data of the dynamic segment (seen as a section).
-      Elf_Data *data = elf_getdata(dynamic_section, NULL);
-      if (data == NULL)
-        continue;
-
-      // Get the index of the section headers string table.
-      size_t string_table_index = 0;
-      ABG_ASSERT (elf_getshdrstrndx(elf, &string_table_index) >= 0);
-
-      size_t dynamic_section_header_entry_size = gelf_fsize(elf,
-                                                            ELF_T_DYN, 1,
-                                                            EV_CURRENT);
-
-      GElf_Shdr link_mem;
-      GElf_Shdr *link =
-        gelf_getshdr(elf_getscn(elf,
-                                dynamic_section_header->sh_link),
-		     &link_mem);
-      ABG_ASSERT(link != NULL);
-
-      size_t num_dynamic_section_entries =
-        dynamic_section_header->sh_size / dynamic_section_header_entry_size;
-
-      // Now walk through all the DT_* data tags that are in the
-      // segment/section
-      for (size_t j = 0; j < num_dynamic_section_entries; ++j)
-        {
-          GElf_Dyn dynamic_section_mem;
-          GElf_Dyn *dynamic_section = gelf_getdyn(data,
-                                                  j,
-                                                  &dynamic_section_mem);
-          if (dynamic_section->d_tag == data_tag)
-            {
-              dt_tag_data.push_back(elf_strptr(elf,
-                                               dynamic_section_header->sh_link,
-					       dynamic_section->d_un.d_val));
-              found = true;
-            }
-        }
-    }
-  return found;
-}
-
-/// Convert the type of ELF file into @ref elf_type.
-///
-/// @param elf the elf handle to use for the query.
-///
-/// @return the @ref elf_type for a given elf type.
-static elf_type
-elf_file_type(Elf* elf)
-{
-  GElf_Ehdr ehdr_mem;
-  GElf_Ehdr *header = gelf_getehdr (elf, &ehdr_mem);
-  vector<string> dt_debug_data;
-
-  switch (header->e_type)
-    {
-    case ET_DYN:
-      if (lookup_data_tag_from_dynamic_segment(elf, DT_DEBUG, dt_debug_data))
-	return ELF_TYPE_PI_EXEC;
-      else
-	return ELF_TYPE_DSO;
-    case ET_EXEC:
-      return ELF_TYPE_EXEC;
-    case ET_REL:
-      return ELF_TYPE_RELOCATABLE;
-    default:
-      return ELF_TYPE_UNKNOWN;
-    }
-}
-
 // ---------------------------------------
 // <location expression evaluation types>
 // ---------------------------------------
@@ -2004,35 +1672,18 @@ struct dwarf_expr_eval_context
 // </location expression evaluation types>
 // ---------------------------------------
 
-/// The context used to build ABI corpus from debug info in DWARF
-/// format.
-///
-/// This context is to be created by create_read_context().  It's then
-/// passed to all the routines that read specific dwarf bits as they
-/// get some important data from it.
+class reader;
+
+typedef shared_ptr<reader> reader_sptr;
+
+/// The DWARF reader used to build the ABI corpus from debug info in
+/// DWARF format.
 ///
-/// When a new data member is added to this context, it must be
-/// initiliazed by the read_context::initiliaze() function.  So please
-/// do not forget.
-class read_context
+/// This type is to be instanciated
+/// abigail::dwarf_reader::reader::create().
+class reader : public elf_based_reader
 {
 public:
-  struct options_type
-  {
-    environment*	env;
-    bool		load_in_linux_kernel_mode;
-    bool		load_all_types;
-    bool		show_stats;
-    bool		do_log;
-
-    options_type()
-      : env(),
-	load_in_linux_kernel_mode(),
-	load_all_types(),
-	show_stats(),
-	do_log()
-    {}
-  };// read_context::options_type
 
   /// A set of containers that contains one container per kind of @ref
   /// die_source.  This allows to associate DIEs to things, depending
@@ -2092,7 +1743,7 @@ public:
     /// Getter for the container associated to DIEs coming from the
     /// same source as a given DIE.
     ///
-    /// @param ctxt the read context to consider.
+    /// @param rdr the DWARF reader to consider.
     ///
     /// @param die the DIE which should have the same source as the
     /// source of the container we want.
@@ -2100,16 +1751,16 @@ public:
     /// @return the container that associates DIEs coming from the
     /// same source as @p die.
     ContainerType&
-    get_container(const read_context& ctxt, const Dwarf_Die *die)
+    get_container(const reader& rdr, const Dwarf_Die *die)
     {
-      const die_source source = ctxt.get_die_source(die);
+      const die_source source = rdr.get_die_source(die);
       return get_container(source);
     }
 
     /// Getter for the container associated to DIEs coming from the
     /// same source as a given DIE.
     ///
-    /// @param ctxt the read context to consider.
+    /// @param rdr the DWARF reader to consider.
     ///
     /// @param die the DIE which should have the same source as the
     /// source of the container we want.
@@ -2117,10 +1768,10 @@ public:
     /// @return the container that associates DIEs coming from the
     /// same source as @p die.
     const ContainerType&
-    get_container(const read_context& ctxt, const Dwarf_Die *die) const
+    get_container(const reader& rdr, const Dwarf_Die *die) const
     {
       return const_cast<die_source_dependant_container_set*>(this)->
-	get_container(ctxt, die);
+	get_container(rdr, die);
     }
 
     /// Clear the container set.
@@ -2133,28 +1784,7 @@ public:
     }
   }; // end die_dependant_container_set
 
-  suppr::suppressions_type	supprs_;
   unsigned short		dwarf_version_;
-  Dwfl_Callbacks		offline_callbacks_;
-  // The set of directories under which to look for debug info.
-  vector<char**>		debug_info_root_paths_;
-  dwfl_sptr			handle_;
-  Dwarf*			dwarf_;
-  // The alternate debug info.  Alternate debug info sections are a
-  // DWARF extension as of DWARF4 and are described at
-  // http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.  Below are
-  // the file desctor used to access the alternate debug info
-  // sections, and the representation of the DWARF debug info.  Both
-  // need to be freed after we are done using them, with fclose and
-  // dwarf_end.
-  int				alt_fd_;
-  Dwarf*			alt_dwarf_;
-  string			alt_debug_info_path_;
-  // The address range of the offline elf file we are looking at.
-  Dwfl_Module*			elf_module_;
-  mutable Elf*			elf_handle_;
-  string			elf_path_;
-  mutable Elf_Scn*		symtab_section_;
   Dwarf_Die*			cur_tu_die_;
   mutable dwarf_expr_eval_context	dwarf_expr_eval_context_;
   // A set of maps (one per kind of die source) that associates a decl
@@ -2210,8 +1840,6 @@ public:
   string_classes_map		decl_only_classes_map_;
   string_enums_map		decl_only_enums_map_;
   die_tu_map_type		die_tu_map_;
-  corpus_group_sptr		cur_corpus_group_;
-  corpus_sptr			cur_corpus_;
   translation_unit_sptr	cur_tu_;
   scope_decl_sptr		nil_scope_;
   scope_stack_type		scope_stack_;
@@ -2228,12 +1856,6 @@ public:
   offset_offset_map_type	alternate_die_parent_map_;
   offset_offset_map_type	type_section_die_parent_map_;
   list<var_decl_sptr>		var_decls_to_add_;
-  vector<string>		dt_needed_;
-  string			dt_soname_;
-  string			elf_architecture_;
-  corpus::exported_decls_builder* exported_decls_builder_;
-  options_type			options_;
-  bool				drop_undefined_syms_;
 #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
   bool				debug_die_canonicalization_is_on_;
   bool				use_canonical_die_comparison_;
@@ -2242,14 +1864,11 @@ public:
   mutable size_t		canonical_propagated_count_;
   mutable size_t		cancelled_propagation_count_;
 
-  read_context();
+protected:
 
-private:
-  mutable symtab_reader::symtab_sptr symtab_;
+  reader() = delete;
 
-public:
-
-  /// Constructor of read_context.
+  /// Constructor of reader.
   ///
   /// @param elf_path the path to the elf file the context is to be
   /// used for.
@@ -2260,14 +1879,14 @@ public:
   /// split file.
   ///
   /// @param environment the environment used by the current context.
-  /// This environment contains resources needed by the reader and by
+  /// This environment contains resources needed by the DWARF 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.
   ///
   /// Please also note that the life time of this environment object
   /// must be greater than the life time of the resulting @ref
-  /// read_context the context uses resources that are allocated in
+  /// reader the context uses resources that are allocated in
   /// the environment.
   ///
   /// @param load_all_types if set to false only the types that are
@@ -2278,36 +1897,23 @@ public:
   /// @param linux_kernel_mode if set to true, then consider the special
   /// linux kernel symbol tables when determining if a symbol is
   /// exported or not.
-  read_context(const string&	elf_path,
-	       const vector<char**>& debug_info_root_paths,
-	       ir::environment* environment,
-	       bool		load_all_types,
-	       bool		linux_kernel_mode)
+  reader(const string&		elf_path,
+	 const vector<char**>&	debug_info_root_paths,
+	 environment&		environment,
+	 bool			load_all_types,
+	 bool			linux_kernel_mode)
+    : elf_based_reader(elf_path,
+		       debug_info_root_paths,
+		       environment)
   {
-    initialize(elf_path, debug_info_root_paths, environment,
-	       load_all_types, linux_kernel_mode);
+    initialize(load_all_types, linux_kernel_mode);
   }
 
-  /// Initializer of read_context.
-  ///
-  /// @param elf_path the path to the elf file the context is to be
-  /// used for.
+public:
+
+  /// Initializer of reader.
   ///
-  /// @param debug_info_root_paths a vector of pointers to the path to
-  /// the root directory under which the debug info is to be found for
-  /// @p elf_path.  Leave this empty if the debug info is not in a
-  /// split file.
-  ///
-  /// @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
-  /// that ABI artifacts that are to be compared all need to be
-  /// created within the same environment.
-  ///
-  /// Please also note that the life time of this environment object
-  /// must be greater than the life time of the resulting @ref
-  /// read_context the context uses resources that are allocated in
-  /// the environment.
+  /// Resets the reader so that it can be re-used to read another binary.
   ///
   /// @param load_all_types if set to false only the types that are
   /// reachable from publicly exported declarations (of functions and
@@ -2318,27 +1924,10 @@ public:
   /// special linux kernel symbol tables when determining if a symbol
   /// is exported or not.
   void
-  initialize(const string&	elf_path,
-	     const vector<char**>& debug_info_root_paths,
-	     ir::environment* environment,
-	     bool		load_all_types,
-	     bool		linux_kernel_mode)
+  initialize(bool load_all_types, bool linux_kernel_mode)
   {
     dwarf_version_ = 0;
-    dwarf_ = 0;
-    handle_.reset();
-    alt_fd_ = 0;
-    alt_dwarf_ = 0;
-    elf_module_ = 0;
-    elf_handle_ = 0;
-    elf_path_ = elf_path;
-    symtab_section_ = 0;
     cur_tu_die_ =  0;
-    exported_decls_builder_ = 0;
-
-    clear_alt_debug_info_data();
-
-    supprs_.clear();
     decl_die_repr_die_offsets_maps_.clear();
     type_die_repr_die_offsets_maps_.clear();
     die_qualified_name_maps_.clear();
@@ -2358,8 +1947,8 @@ public:
     types_to_canonicalize_.clear();
     decl_only_classes_map_.clear();
     die_tu_map_.clear();
-    cur_corpus_group_.reset();
-    cur_corpus_.reset();
+    corpus().reset();
+    corpus_group().reset();
     cur_tu_.reset();
     primary_die_parent_map_.clear();
     tu_die_imported_unit_points_map_.clear();
@@ -2368,20 +1957,9 @@ public:
     alternate_die_parent_map_.clear();
     type_section_die_parent_map_.clear();
     var_decls_to_add_.clear();
-    dt_needed_.clear();
-    dt_soname_.clear();
-    elf_architecture_.clear();
-
-    symtab_.reset();
-
     clear_per_translation_unit_data();
-
-    memset(&offline_callbacks_, 0, sizeof(offline_callbacks_));
-    create_default_dwfl(debug_info_root_paths);
-    options_.env = environment;
-    options_.load_in_linux_kernel_mode = linux_kernel_mode;
-    options_.load_all_types = load_all_types;
-    drop_undefined_syms_ = false;
+    options().load_in_linux_kernel_mode = linux_kernel_mode;
+    options().load_all_types = load_all_types;
 #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
     debug_die_canonicalization_is_on_ =
       environment->debug_die_canonicalization_is_on();
@@ -2393,27 +1971,349 @@ public:
     load_in_linux_kernel_mode(linux_kernel_mode);
   }
 
-  /// Clear the resources related to the alternate DWARF data.
+    /// Initializer of reader.
+  ///
+  /// Resets the reader so that it can be re-used to read another binary.
+  ///
+  /// @param elf_path the path to the new ELF file.
+  ///
+  /// @param debug_info_root_paths the vector of debug-info path to
+  /// look for split debug info.
+  ///
+  /// @param load_all_types if set to false only the types that are
+  /// reachable from publicly exported declarations (of functions and
+  /// variables) are read.  If set to true then all types found in the
+  /// debug information are loaded.
+  ///
+  /// @param linux_kernel_mode if set to true, then consider the
+  /// special linux kernel symbol tables when determining if a symbol
+  /// is exported or not.
   void
-  clear_alt_debug_info_data()
+  initialize(const string&		elf_path,
+	     const vector<char**>&	debug_info_root_paths,
+	     bool			load_all_types,
+	     bool			linux_kernel_mode)
   {
-    if (alt_fd_)
-      {
-	close(alt_fd_);
-	alt_fd_ = 0;
-	if (alt_dwarf_)
-	  {
-	    dwarf_end(alt_dwarf_);
-	    alt_dwarf_ = 0;
-	  }
-	alt_debug_info_path_.clear();
-      }
+    reset(elf_path, debug_info_root_paths);
+    initialize(load_all_types, linux_kernel_mode);
+  }
+
+  /// Create an instance of DWARF Reader.
+  ///
+  /// @param elf_path the path to the ELF file to read from.
+  ///
+  /// @param debug_info_root_paths a vector of paths where to look up
+  /// split debug info files.
+  ///
+  /// @param environment the environment to be used by the reader.
+  ///
+  /// @param load_all_types if set to false only the types that are
+  /// reachable from publicly exported declarations (of functions and
+  /// variables) are read.  If set to true then all types found in the
+  /// debug information are loaded.
+  ///
+  /// @param linux_kernel_mode if set to true, then consider the
+  /// special linux kernel symbol tables when determining if a symbol
+  /// is exported or not.
+  static dwarf_reader::reader_sptr
+  create(const std::string&	elf_path,
+	 const vector<char**>&	debug_info_root_paths,
+	 environment&		environment,
+	 bool			load_all_types,
+	 bool			linux_kernel_mode)
+  {
+    reader_sptr result(new reader(elf_path, debug_info_root_paths,
+				  environment, load_all_types,
+				  linux_kernel_mode));
+    return result;
   }
 
-  /// Detructor of the @ref read_context type.
-  ~read_context()
+  /// Destructor of the @ref reader type.
+  ~reader()
   {
-    clear_alt_debug_info_data();
+  }
+
+  /// Read and analyze the ELF and DWARF information associated with
+  /// the underlying ELF file and build an ABI corpus out of it.
+  ///
+  /// @param status output parameter.  This is set to the status of
+  /// the analysis of the debug info.
+  ///
+  /// @return the resulting ABI corpus.
+  corpus_sptr
+  read_corpus(status& status)
+  {
+    status = STATUS_UNKNOWN;
+
+    // Load the generic ELF parts of the corpus.
+    elf_reader::reader::read_corpus(status);
+
+    if ((status & STATUS_NO_SYMBOLS_FOUND)
+	|| !(status & STATUS_OK))
+      // Either we couldn't find ELF symbols or something went badly
+      // wrong.  There is nothing we can do with this ELF file.  Bail
+      // out.
+      return corpus_sptr();
+
+    // If we couldn't find debug info from the elf path, then say it.
+    if (dwarf_debug_info() == nullptr)
+      status |= STATUS_DEBUG_INFO_NOT_FOUND;
+
+    {
+      string alt_di_path;
+      if (refers_to_alt_debug_info(alt_di_path)
+	  && !alternate_dwarf_debug_info())
+	status |= STATUS_ALT_DEBUG_INFO_NOT_FOUND;
+    }
+
+    if (// If debug info was found but not the required alternate debug
+	// info ...
+	((status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
+	 && !(status & STATUS_DEBUG_INFO_NOT_FOUND)))
+      // ... then we cannot handle the binary.
+      return corpus_sptr();
+
+    // Read the variable and function descriptions from the debug info
+    // we have, through the dwfl handle.
+    corpus_sptr corp = read_debug_info_into_corpus();
+
+    status |= STATUS_OK;
+
+    return corp;
+  }
+
+  /// Read an analyze the DWARF information.
+  ///
+  /// Construct an ABI corpus from it.
+  ///
+  /// This is a sub-routine of abigail::dwarf_reader::reader::read_corpus().
+  ///
+  /// @return the resulting ABI corpus.
+  corpus_sptr
+  read_debug_info_into_corpus()
+  {
+    clear_per_corpus_data();
+
+    // First set some mundane properties of the corpus gathered from
+    // ELF.
+    corpus::origin origin = corpus::DWARF_ORIGIN;
+    if (is_linux_kernel(elf_handle()))
+      origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
+    corpus()->set_origin(origin);
+
+    if (origin & corpus::LINUX_KERNEL_BINARY_ORIGIN
+	&& !env().user_set_analyze_exported_interfaces_only())
+      // So we are looking at the Linux Kernel and the user has not set
+      // any particular option regarding the amount of types to analyse.
+      // In that case, we need to only analyze types that are reachable
+      // from exported interfaces otherwise we get such a massive amount
+      // of type DIEs to look at that things are just too slow down the
+      // road.
+      env().analyze_exported_interfaces_only(true);
+
+    corpus()->set_soname(dt_soname());
+    corpus()->set_needed(dt_needed());
+    corpus()->set_architecture_name(elf_architecture());
+    if (corpus_group_sptr group = corpus_group())
+      group->add_corpus(corpus());
+
+    // Set symbols information to the corpus.
+    corpus()->set_symtab(symtab());
+
+    // Get out now if no debug info is found.
+    if (!dwarf_debug_info())
+      return corpus();
+
+    uint8_t address_size = 0;
+    size_t header_size = 0;
+
+#ifdef WITH_DEBUG_SELF_COMPARISON
+    if (env().self_comparison_debug_is_on())
+      env().set_self_comparison_debug_input(corpus());
+#endif
+
+    // Walk all the DIEs of the debug info to build a DIE -> parent map
+    // useful for get_die_parent() to work.
+    {
+      tools_utils::timer t;
+      if (do_log())
+	{
+	  cerr << "building die -> parent maps ...";
+	  t.start();
+	}
+
+      build_die_parent_maps();
+
+      if (do_log())
+	{
+	  t.stop();
+	  cerr << " DONE@" << corpus()->get_path()
+	       << ":"
+	       << t
+	       << "\n";
+	}
+    }
+
+    env().canonicalization_is_done(false);
+
+    {
+      tools_utils::timer t;
+      if (do_log())
+	{
+	  cerr << "building the libabigail internal representation ...";
+	  t.start();
+	}
+      // And now walk all the DIEs again to build the libabigail IR.
+      Dwarf_Half dwarf_vers = 0;
+      for (Dwarf_Off offset = 0, next_offset = 0;
+	   (dwarf_next_unit(const_cast<Dwarf*>(dwarf_debug_info()),
+			    offset, &next_offset, &header_size,
+			    &dwarf_vers, NULL, &address_size, NULL,
+			    NULL, NULL) == 0);
+	   offset = next_offset)
+	{
+	  Dwarf_Off die_offset = offset + header_size;
+	  Dwarf_Die unit;
+	  if (!dwarf_offdie(const_cast<Dwarf*>(dwarf_debug_info()),
+			    die_offset, &unit)
+	      || dwarf_tag(&unit) != DW_TAG_compile_unit)
+	    continue;
+
+	  dwarf_version(dwarf_vers);
+
+	  address_size *= 8;
+
+	  // Build a translation_unit IR node from cu; note that cu must
+	  // be a DW_TAG_compile_unit die.
+	  translation_unit_sptr ir_node =
+	    build_translation_unit_and_add_to_ir(*this, &unit, address_size);
+	  ABG_ASSERT(ir_node);
+	}
+      if (do_log())
+	{
+	  t.stop();
+	  cerr << " DONE@" << corpus()->get_path()
+	       << ":"
+	       << t
+	       << "\n";
+
+	  cerr << "Number of aggregate types compared: "
+	       << compare_count_ << "\n"
+	       << "Number of canonical types propagated: "
+	       << canonical_propagated_count_ << "\n"
+	       << "Number of cancelled propagated canonical types:"
+	       << cancelled_propagation_count_ << "\n";
+	}
+    }
+
+    {
+      tools_utils::timer t;
+      if (do_log())
+	{
+	  cerr << "resolving declaration only classes ...";
+	  t.start();
+	}
+      resolve_declaration_only_classes();
+      if (do_log())
+	{
+	  t.stop();
+	  cerr << " DONE@" << corpus()->get_path()
+	       << ":"
+	       << t
+	       <<"\n";
+	}
+    }
+
+    {
+      tools_utils::timer t;
+      if (do_log())
+	{
+	  cerr << "resolving declaration only enums ...";
+	  t.start();
+	}
+      resolve_declaration_only_enums();
+      if (do_log())
+	{
+	  t.stop();
+	  cerr << " DONE@" << corpus()->get_path()
+	       << ":"
+	       << t
+	       <<"\n";
+	}
+    }
+
+    {
+      tools_utils::timer t;
+      if (do_log())
+	{
+	  cerr << "fixing up functions with linkage name but "
+	       << "no advertised underlying symbols ....";
+	  t.start();
+	}
+      fixup_functions_with_no_symbols();
+      if (do_log())
+	{
+	  t.stop();
+	  cerr << " DONE@" << corpus()->get_path()
+	       <<":"
+	       << t
+	       <<"\n";
+	}
+    }
+
+    /// Now, look at the types that needs to be canonicalized after the
+    /// translation has been constructed (which is just now) and
+    /// canonicalize them.
+    ///
+    /// These types need to be constructed at the end of the translation
+    /// unit reading phase because some types are modified by some DIEs
+    /// even after the principal DIE describing the type has been read;
+    /// this happens for clones of virtual destructors (for instance) or
+    /// even for some static data members.  We need to do that for types
+    /// are in the alternate debug info section and for types that in
+    /// the main debug info section.
+    {
+      tools_utils::timer t;
+      if (do_log())
+	{
+	  cerr << "perform late type canonicalizing ...\n";
+	  t.start();
+	}
+
+      perform_late_type_canonicalizing();
+      if (do_log())
+	{
+	  t.stop();
+	  cerr << "late type canonicalizing DONE@"
+	       << corpus()->get_path()
+	       << ":"
+	       << t
+	       << "\n";
+	}
+    }
+
+    env().canonicalization_is_done(true);
+
+    {
+      tools_utils::timer t;
+      if (do_log())
+	{
+	  cerr << "sort functions and variables ...";
+	  t.start();
+	}
+      corpus()->sort_functions();
+      corpus()->sort_variables();
+      if (do_log())
+	{
+	  t.stop();
+	  cerr << " DONE@" << corpus()->get_path()
+	       << ":"
+	       << t
+	       <<" \n";
+	}
+    }
+
+    return corpus();
   }
 
   /// Clear the data that is relevant only for the current translation
@@ -2442,23 +2342,16 @@ public:
   /// Getter for the current environment.
   ///
   /// @return the current environment.
-  const ir::environment*
-  env() const
-  {return options_.env;}
+  environment&
+  env()
+  {return options().env;}
 
   /// Getter for the current environment.
   ///
   /// @return the current environment.
-  ir::environment*
-  env()
-  {return options_.env;}
-
-  /// Setter for the current environment.
-  ///
-  /// @param env the new current environment.
-  void
-  env(ir::environment* env)
-  {options_.env = env;}
+  const environment&
+  env() const
+  {return const_cast<reader*>(this)->env();}
 
   /// Getter for the flag that tells us if we are dropping functions
   /// and variables that have undefined symbols.
@@ -2467,7 +2360,7 @@ public:
   /// undefined symbols.
   bool
   drop_undefined_syms() const
-  {return drop_undefined_syms_;}
+  {return options().drop_undefined_syms;}
 
   /// Setter for the flag that tells us if we are dropping functions
   /// and variables that have undefined symbols.
@@ -2475,67 +2368,9 @@ public:
   /// @param f the new value of the flag.
   void
   drop_undefined_syms(bool f)
-  {drop_undefined_syms_ = f;}
-
-  /// Getter of the suppression specifications to be used during
-  /// ELF/DWARF parsing.
-  ///
-  /// @return the suppression specifications.
-  const suppr::suppressions_type&
-  get_suppressions() const
-  {return supprs_;}
-
-  /// Getter of the suppression specifications to be used during
-  /// ELF/DWARF parsing.
-  ///
-  /// @return the suppression specifications.
-  suppr::suppressions_type&
-  get_suppressions()
-  {return supprs_;}
-
-  /// Getter for the callbacks of the Dwarf Front End library of
-  /// elfutils that is used by this reader to read dwarf.
-  ///
-  /// @return the callbacks.
-  const Dwfl_Callbacks*
-  offline_callbacks() const
-  {return &offline_callbacks_;}
-
-  /// Getter for the callbacks of the Dwarf Front End library of
-  /// elfutils that is used by this reader to read dwarf.
-  /// @returnthe callbacks
-  Dwfl_Callbacks*
-  offline_callbacks()
-  {return &offline_callbacks_;}
-
-  /// Constructor for a default Dwfl handle that knows how to load debug
-  /// info from a library or executable elf file.
-  ///
-  /// @param debug_info_root_paths a vector of pointers to the root
-  /// path under which to look for the debug info of the elf files
-  /// that are later handled by the Dwfl.  This is for cases where the
-  /// debug info is split into a different file from the binary we
-  /// want to inspect.  On Red Hat compatible systems, this root path
-  /// is usually /usr/lib/debug by default.  If this argument is set
-  /// to the empty set, then "./debug" and /usr/lib/debug will be
-  /// searched for sub-directories containing the debug info file.
-  /// Note that for now, elfutils wants this path to be absolute
-  /// otherwise things just don't work and the debug info is not
-  /// found.
-  ///
-  /// @return the constructed Dwfl handle.
-  void
-  create_default_dwfl(const vector<char**>& debug_info_root_paths)
-  {
-    offline_callbacks()->find_debuginfo = dwfl_standard_find_debuginfo;
-    offline_callbacks()->section_address = dwfl_offline_section_address;
-    offline_callbacks()->debuginfo_path =
-      debug_info_root_paths.empty() ? 0 : debug_info_root_paths.front();
-    handle_.reset(dwfl_begin(offline_callbacks()),
-		  dwfl_deleter());
-    debug_info_root_paths_ = debug_info_root_paths;
-  }
+  {options().drop_undefined_syms = f;}
 
+  /// Getter of the DWARF version.
   unsigned short
   dwarf_version() const
   {return dwarf_version_;}
@@ -2544,47 +2379,9 @@ public:
   dwarf_version(unsigned short v)
   {dwarf_version_ = v;}
 
-  /// Getter for a smart pointer to a handle on the dwarf front end
-  /// library that we use to read dwarf.
-  ///
-  /// @return the dwfl handle.
-  dwfl_sptr
-  dwfl_handle() const
-  {return handle_;}
-
-  /// Setter for a smart pointer to a handle on the dwarf front end
-  /// library that we use to read dwarf.
-  ///
-  /// @param h the new dwfl handle.
-  void
-  dwfl_handle(dwfl_sptr& h)
-  {handle_ = h;}
-
-  Dwfl_Module*
-  elf_module() const
-  {return elf_module_;}
-
-  /// Return the ELF descriptor for the binary we are analizing.
-  ///
-  /// @return a pointer to the Elf descriptor representing the binary
-  /// we are analizing.
-  Elf*
-  elf_handle() const
-  {
-    if (elf_handle_ == 0)
-      {
-	if (elf_module())
-	  {
-	    GElf_Addr bias = 0;
-	    elf_handle_ = dwfl_module_getelf(elf_module(), &bias);
-	  }
-      }
-    return elf_handle_;
-  }
-
   /// Return the ELF descriptor used for DWARF access.
   ///
-  /// This can be the same as read_context::elf_handle() above, if the
+  /// This can be the same as reader::elf_handle() above, if the
   /// DWARF info is in the same ELF file as the one of the binary we
   /// are analizing.  It is different if e.g, the debug info is split
   /// from the ELF file we are analizing.
@@ -2593,7 +2390,7 @@ public:
   /// info.
   Elf*
   dwarf_elf_handle() const
-  {return dwarf_getelf(dwarf());}
+  {return dwarf_getelf(const_cast<Dwarf*>(dwarf_debug_info()));}
 
   /// Test if the debug information is in a separate ELF file wrt the
   /// main ELF file of the program (application or shared library) we
@@ -2606,122 +2403,24 @@ public:
   dwarf_is_splitted() const
   {return dwarf_elf_handle() != elf_handle();}
 
-  /// Add paths to the set of paths under which to look for split
-  /// debuginfo files.
-  ///
-  /// @param debug_info_root_paths the paths to add.
-  void
-  add_debug_info_root_paths(const vector<char **>& debug_info_root_paths)
-  {
-    debug_info_root_paths_.insert(debug_info_root_paths_.end(),
-				  debug_info_root_paths.begin(),
-				  debug_info_root_paths.end());
-  }
-
-  /// Add a path to the set of paths under which to look for split
-  /// debuginfo files.
-  ///
-  /// @param debug_info_root_path the path to add.
-  void
-  add_debug_info_root_path(char** debug_info_root_path)
-  {debug_info_root_paths_.push_back(debug_info_root_path);}
-
-  /// Find the alternate debuginfo file associated to a given elf file.
-  ///
-  /// @param elf_module represents the elf file to consider.
-  ///
-  /// @param alt_file_name the resulting path to the alternate
-  /// debuginfo file found.  This is set iff the function returns a
-  /// non-nil value.
-  Dwarf*
-  find_alt_debug_info(Dwfl_Module *elf_module,
-		      string& alt_file_name,
-		      int& alt_fd)
-  {
-    Dwarf *result = 0;
-    result = dwarf_reader::find_alt_debug_info(elf_module,
-					       debug_info_root_paths_,
-					       alt_file_name, alt_fd);
-    return result;
-  }
-
-  /// Load the debug info associated with an elf file that is at a
-  /// given path.
-  ///
-  /// @return a pointer to the DWARF debug info pointer upon
-  /// successful debug info loading, NULL otherwise.
-  Dwarf*
-  load_debug_info()
-  {
-    if (!dwfl_handle())
-      return 0;
-
-    if (dwarf_)
-      return dwarf_;
-
-    elf_module_ =
-      dwfl_report_offline(dwfl_handle().get(),
-			  basename(const_cast<char*>(elf_path().c_str())),
-			  elf_path().c_str(),
-			  -1);
-    dwfl_report_end(dwfl_handle().get(), 0, 0);
-
-    Dwarf_Addr bias = 0;
-    dwarf_ = dwfl_module_getdwarf(elf_module_, &bias);
-    // Look for split debuginfo files under multiple possible
-    // debuginfo roots.
-    for (vector<char**>::const_iterator i = debug_info_root_paths_.begin();
-	 dwarf_ == 0 && i != debug_info_root_paths_.end();
-	 ++i)
-      {
-	offline_callbacks()->debuginfo_path = *i;
-	dwarf_ = dwfl_module_getdwarf(elf_module_, &bias);
-      }
-
-    if (!alt_dwarf_)
-      alt_dwarf_ = find_alt_debug_info(elf_module_,
-				       alt_debug_info_path_,
-				       alt_fd_);
-
-    return dwarf_;
-  }
-
-  /// Return the main debug info we are looking at.
-  ///
-  /// @return the main debug info.
-  Dwarf*
-  dwarf() const
-  {return dwarf_;}
-
-  /// Return the alternate debug info we are looking at.
-  ///
-  /// Note that "alternate debug info sections" is a GNU extension as
-  /// of DWARF4 and is described at
-  /// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1
-  ///
-  /// @return the alternate debug info.
-  Dwarf*
-  alt_dwarf() const
-  {return alt_dwarf_;}
-
   /// Return the correct debug info, depending on the DIE source we
   /// are looking at.
   ///
   /// @param source the DIE source to consider.
   ///
   /// @return the right debug info, depending on @p source.
-  Dwarf*
+  const Dwarf*
   dwarf_per_die_source(die_source source) const
   {
-    Dwarf *result = 0;
+    const Dwarf *result = 0;
     switch(source)
       {
       case PRIMARY_DEBUG_INFO_DIE_SOURCE:
       case TYPE_UNIT_DIE_SOURCE:
-	result = dwarf();
+	result = dwarf_debug_info();
 	break;
       case ALT_DEBUG_INFO_DIE_SOURCE:
-	result = alt_dwarf();
+	result = alternate_dwarf_debug_info();
 	break;
       case NO_DEBUG_INFO_DIE_SOURCE:
       case NUMBER_OF_DIE_SOURCES:
@@ -2730,25 +2429,12 @@ public:
     return result;
   }
 
-  /// Return the path to the alternate debug info as contained in the
-  /// .gnu_debugaltlink section of the main elf file.
-  ///
-  /// Note that "alternate debug info sections" is a GNU extension as
-  /// of DWARF4 and is described at
-  /// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1
-  ///
-  /// @return the path to the alternate debug info file, or an empty
-  /// path if no alternate debug info file is associated.
-  const string&
-  alt_debug_info_path() const
-  {return alt_debug_info_path_;}
-
   /// Return the path to the ELF path we are reading.
   ///
   /// @return the elf path.
   const string&
   elf_path() const
-  {return elf_path_;}
+  {return corpus_path();}
 
   const Dwarf_Die*
   cur_tu_die() const
@@ -2815,9 +2501,9 @@ public:
   {
     offset_offset_map_type &canonical_dies =
       die_as_type
-      ? const_cast<read_context*>(this)->canonical_type_die_offsets_.
+      ? const_cast<reader*>(this)->canonical_type_die_offsets_.
       get_container(*this, die)
-      : const_cast<read_context*>(this)->canonical_decl_die_offsets_.
+      : const_cast<reader*>(this)->canonical_decl_die_offsets_.
       get_container(*this, die);
 
     Dwarf_Die canonical_die;
@@ -2882,13 +2568,14 @@ public:
     // with a vector of offsets of potentially equivalent DIEs.
     istring_dwarf_offsets_map_type& map =
       die_as_type
-      ? (const_cast<read_context*>(this)->
+      ? (const_cast<reader*>(this)->
 	 type_die_repr_die_offsets_maps().get_container(source))
-      : (const_cast<read_context*>(this)->
+      : (const_cast<reader*>(this)->
 	 decl_die_repr_die_offsets_maps().get_container(source));
 
     Dwarf_Die die;
-    ABG_ASSERT(dwarf_offdie(dwarf_per_die_source(source), die_offset, &die));
+    ABG_ASSERT(dwarf_offdie(const_cast<Dwarf*>(dwarf_per_die_source(source)),
+			    die_offset, &die));
 
     // The variable repr is the the string representation of 'die'.
     //
@@ -2963,9 +2650,9 @@ public:
 
     offset_offset_map_type &canonical_dies =
       die_as_type
-      ? const_cast<read_context*>(this)->canonical_type_die_offsets_.
+      ? const_cast<reader*>(this)->canonical_type_die_offsets_.
       get_container(source)
-      : const_cast<read_context*>(this)->canonical_decl_die_offsets_.
+      : const_cast<reader*>(this)->canonical_decl_die_offsets_.
       get_container(source);
 
     Dwarf_Off die_offset = dwarf_dieoffset(const_cast<Dwarf_Die*>(die));
@@ -2980,9 +2667,9 @@ public:
     // with a vector of offsets of potentially equivalent DIEs.
     istring_dwarf_offsets_map_type& map =
       die_as_type
-      ? (const_cast<read_context*>(this)->
+      ? (const_cast<reader*>(this)->
 	 type_die_repr_die_offsets_maps().get_container(*this, die))
-      : (const_cast<read_context*>(this)->
+      : (const_cast<reader*>(this)->
 	 decl_die_repr_die_offsets_maps().get_container(*this, die));
 
     // The variable repr is the the string representation of 'die'.
@@ -3008,7 +2695,7 @@ public:
 	cur_die_offset = *o;
 	get_die_from_offset(source, cur_die_offset, &canonical_die);
 	// compare die and canonical_die.
-	if (compare_dies_during_canonicalization(const_cast<read_context&>(*this),
+	if (compare_dies_during_canonicalization(const_cast<reader&>(*this),
 						 die, &canonical_die,
 						 /*update_canonical_dies_on_the_fly=*/true))
 	  {
@@ -3055,9 +2742,9 @@ public:
 
     offset_offset_map_type &canonical_dies =
       die_as_type
-      ? const_cast<read_context*>(this)->canonical_type_die_offsets_.
+      ? const_cast<reader*>(this)->canonical_type_die_offsets_.
       get_container(source)
-      : const_cast<read_context*>(this)->canonical_decl_die_offsets_.
+      : const_cast<reader*>(this)->canonical_decl_die_offsets_.
       get_container(source);
 
     Dwarf_Off initial_die_offset = dwarf_dieoffset(const_cast<Dwarf_Die*>(die));
@@ -3077,9 +2764,9 @@ public:
     // with a vector of offsets of potentially equivalent DIEs.
     istring_dwarf_offsets_map_type& map =
       die_as_type
-      ? (const_cast<read_context*>(this)->
+      ? (const_cast<reader*>(this)->
 	 type_die_repr_die_offsets_maps().get_container(*this, die))
-      : (const_cast<read_context*>(this)->
+      : (const_cast<reader*>(this)->
 	 decl_die_repr_die_offsets_maps().get_container(*this, die));
 
     // The variable repr is the the string representation of 'die'.
@@ -3115,7 +2802,7 @@ public:
 	Dwarf_Off die_offset = i->second[n];
 	get_die_from_offset(source, die_offset, &canonical_die);
 	// compare die and canonical_die.
-	if (compare_dies_during_canonicalization(const_cast<read_context&>(*this),
+	if (compare_dies_during_canonicalization(const_cast<reader&>(*this),
 						 die, &canonical_die,
 						 /*update_canonical_dies_on_the_fly=*/true))
 	  {
@@ -3198,10 +2885,10 @@ public:
     if (tag == DW_TAG_compile_unit
 	|| tag == DW_TAG_partial_unit)
       {
-	Dwarf *die_dwarf = dwarf_cu_getdwarf(cu_die.cu);
-	if (dwarf() == die_dwarf)
+	const Dwarf *die_dwarf = dwarf_cu_getdwarf(cu_die.cu);
+	if (dwarf_debug_info() == die_dwarf)
 	  source = PRIMARY_DEBUG_INFO_DIE_SOURCE;
-	else if (alt_dwarf() == die_dwarf)
+	else if (alternate_dwarf_debug_info() == die_dwarf)
 	  source = ALT_DEBUG_INFO_DIE_SOURCE;
 	else
 	  ABG_ASSERT_NOT_REACHED;
@@ -3226,9 +2913,11 @@ public:
   get_die_from_offset(die_source source, Dwarf_Off offset, Dwarf_Die *die) const
   {
     if (source == TYPE_UNIT_DIE_SOURCE)
-      ABG_ASSERT(dwarf_offdie_types(dwarf_per_die_source(source), offset, die));
+      ABG_ASSERT(dwarf_offdie_types(const_cast<Dwarf*>(dwarf_per_die_source(source)),
+				    offset, die));
     else
-      ABG_ASSERT(dwarf_offdie(dwarf_per_die_source(source), offset, die));
+      ABG_ASSERT(dwarf_offdie(const_cast<Dwarf*>(dwarf_per_die_source(source)),
+			      offset, die));
   }
 
 public:
@@ -3331,9 +3020,9 @@ public:
 
     if (i == map.end())
       {
-	read_context& ctxt  = *const_cast<read_context*>(this);
-	string qualified_name = die_qualified_name(ctxt, die, where_offset);
-	interned_string istr = env()->intern(qualified_name);
+	reader& rdr  = *const_cast<reader*>(this);
+	string qualified_name = die_qualified_name(rdr, die, where_offset);
+	interned_string istr = env().intern(qualified_name);
 	map[die_offset] = istr;
 	return istr;
       }
@@ -3356,7 +3045,7 @@ public:
   interned_string
   get_die_qualified_name(Dwarf_Die *die, size_t where_offset) const
   {
-    return const_cast<read_context*>(this)->
+    return const_cast<reader*>(this)->
       get_die_qualified_name(die, where_offset);
   }
 
@@ -3384,10 +3073,10 @@ public:
 
     // The name of the translation unit die is "".
     if (die == cur_tu_die())
-      return env()->intern("");
+      return env().intern("");
 
     die_istring_map_type& map =
-      die_qualified_name_maps_.get_container(*const_cast<read_context*>(this),
+      die_qualified_name_maps_.get_container(*const_cast<reader*>(this),
 					     die);
 
     size_t die_offset = dwarf_dieoffset(const_cast<Dwarf_Die*>(die));
@@ -3396,7 +3085,7 @@ public:
 
     if (i == map.end())
       {
-	read_context& ctxt  = *const_cast<read_context*>(this);
+	reader& rdr  = *const_cast<reader*>(this);
 	string qualified_name;
 	int tag = dwarf_tag(const_cast<Dwarf_Die*>(die));
 	if ((tag == DW_TAG_structure_type
@@ -3410,9 +3099,9 @@ public:
 	  }
 	else
 	  qualified_name =
-	    die_qualified_type_name(ctxt, die, where_offset);
+	    die_qualified_type_name(rdr, die, where_offset);
 
-	interned_string istr = env()->intern(qualified_name);
+	interned_string istr = env().intern(qualified_name);
 	map[die_offset] = istr;
 	return istr;
       }
@@ -3442,7 +3131,7 @@ public:
   {
     ABG_ASSERT(die);
     die_istring_map_type& map =
-      die_pretty_type_repr_maps_.get_container(*const_cast<read_context*>(this),
+      die_pretty_type_repr_maps_.get_container(*const_cast<reader*>(this),
 					       die);
 
     size_t die_offset = dwarf_dieoffset(const_cast<Dwarf_Die*>(die));
@@ -3450,10 +3139,10 @@ public:
 
     if (i == map.end())
       {
-	read_context& ctxt = *const_cast<read_context*>(this);
+	reader& rdr = *const_cast<reader*>(this);
 	string pretty_representation =
-	  die_pretty_print_type(ctxt, die, where_offset);
-	interned_string istr = env()->intern(pretty_representation);
+	  die_pretty_print_type(rdr, die, where_offset);
+	interned_string istr = env().intern(pretty_representation);
 	map[die_offset] = istr;
 	return istr;
       }
@@ -3479,7 +3168,7 @@ public:
     ABG_ASSERT(die);
 
     die_istring_map_type& map =
-      die_pretty_repr_maps_.get_container(*const_cast<read_context*>(this),
+      die_pretty_repr_maps_.get_container(*const_cast<reader*>(this),
 					  die);
 
     size_t die_offset = dwarf_dieoffset(const_cast<Dwarf_Die*>(die));
@@ -3487,10 +3176,10 @@ public:
 
     if (i == map.end())
       {
-	read_context& ctxt = *const_cast<read_context*>(this);
+	reader& rdr = *const_cast<reader*>(this);
 	string pretty_representation =
-	  die_pretty_print(ctxt, die, where_offset);
-	interned_string istr = env()->intern(pretty_representation);
+	  die_pretty_print(rdr, die, where_offset);
+	interned_string istr = env().intern(pretty_representation);
 	map[die_offset] = istr;
 	return istr;
       }
@@ -3704,7 +3393,8 @@ public:
   odr_is_relevant(Dwarf_Off die_offset, die_source source) const
   {
     Dwarf_Die die;
-    ABG_ASSERT(dwarf_offdie(dwarf_per_die_source(source), die_offset, &die));
+    ABG_ASSERT(dwarf_offdie(const_cast<Dwarf*>(dwarf_per_die_source(source)),
+			    die_offset, &die));
     return odr_is_relevant(&die);
   }
 
@@ -3862,9 +3552,9 @@ public:
   {
     offset_offset_map_type &canonical_dies =
       die_as_type
-      ? const_cast<read_context*>(this)->canonical_type_die_offsets_.
+      ? const_cast<reader*>(this)->canonical_type_die_offsets_.
       get_container(source)
-      : const_cast<read_context*>(this)->canonical_decl_die_offsets_.
+      : const_cast<reader*>(this)->canonical_decl_die_offsets_.
       get_container(source);
 
     set_canonical_die_offset(canonical_dies,
@@ -3932,9 +3622,9 @@ public:
   {
     offset_offset_map_type &canonical_dies =
       die_as_type
-      ? const_cast<read_context*>(this)->canonical_type_die_offsets_.
+      ? const_cast<reader*>(this)->canonical_type_die_offsets_.
       get_container(source)
-      : const_cast<read_context*>(this)->canonical_decl_die_offsets_.
+      : const_cast<reader*>(this)->canonical_decl_die_offsets_.
       get_container(source);
 
     return get_canonical_die_offset(canonical_dies, die_offset);
@@ -3958,9 +3648,9 @@ public:
   {
     offset_offset_map_type &canonical_dies =
       die_as_type
-      ? const_cast<read_context*>(this)->canonical_type_die_offsets_.
+      ? const_cast<reader*>(this)->canonical_type_die_offsets_.
       get_container(source)
-      : const_cast<read_context*>(this)->canonical_decl_die_offsets_.
+      : const_cast<reader*>(this)->canonical_decl_die_offsets_.
       get_container(source);
 
     return canonical_dies.erase(die_offset);
@@ -3999,7 +3689,7 @@ public:
   ///
   /// Note that the DIE must have been associated to type by a
   /// previous invocation of the function
-  /// read_context::associate_die_to_type().
+  /// reader::associate_die_to_type().
   ///
   /// @param die the DIE to consider.
   ///
@@ -4020,7 +3710,7 @@ public:
   ///
   /// Note that the DIE must have been associated to type by a
   /// previous invocation of the function
-  /// read_context::associate_die_to_type().
+  /// reader::associate_die_to_type().
   ///
   /// @param die_offset the offset of the DIE to consider.
   ///
@@ -4076,7 +3766,7 @@ public:
   /// built.
   const die_class_or_union_map_type&
   die_wip_classes_map(die_source source) const
-  {return const_cast<read_context*>(this)->die_wip_classes_map(source);}
+  {return const_cast<reader*>(this)->die_wip_classes_map(source);}
 
   /// Getter of a map that associates a die that represents a
   /// class/struct with the declaration of the class, while the class
@@ -4113,7 +3803,7 @@ public:
   /// @return the map of wip function types.
   const die_function_type_map_type&
   die_wip_function_types_map(die_source source) const
-  {return const_cast<read_context*>(this)->die_wip_function_types_map(source);}
+  {return const_cast<reader*>(this)->die_wip_function_types_map(source);}
 
   /// Getter for a map that associates a die (that represents a
   /// function type) whith a function type, while the function type is
@@ -4262,16 +3952,16 @@ public:
     if (!l || !r)
       return !!l == !!r;
 
-    const environment* e = l->get_environment();
-    ABG_ASSERT(!e->canonicalization_is_done());
+    const environment& e = l->get_environment();
+    ABG_ASSERT(!e.canonicalization_is_done());
 
-    e->priv_->allow_type_comparison_results_caching(true);
-    bool s0 = e->decl_only_class_equals_definition();
-    e->decl_only_class_equals_definition(true);
+    e.priv_->allow_type_comparison_results_caching(true);
+    bool s0 = e.decl_only_class_equals_definition();
+    e.decl_only_class_equals_definition(true);
     bool equal = l == r;
-    e->decl_only_class_equals_definition(s0);
-    e->priv_->clear_type_comparison_results_cache();
-    e->priv_->allow_type_comparison_results_caching(false);
+    e.decl_only_class_equals_definition(s0);
+    e.priv_->clear_type_comparison_results_cache();
+    e.priv_->allow_type_comparison_results_caching(false);
     return equal;
   }
 
@@ -4329,7 +4019,7 @@ public:
 	// So get the classes that might define the current
 	// declarations which name is i->first.
 	const type_base_wptrs_type *classes =
-	  lookup_class_types(i->first, *current_corpus());
+	  lookup_class_types(i->first, *corpus());
 	if (!classes)
 	  continue;
 
@@ -4565,7 +4255,7 @@ public:
 	// So get the enums that might define the current
 	// declarations which name is i->first.
 	const type_base_wptrs_type *enums =
-	  lookup_enum_types(i->first, *current_corpus());
+	  lookup_enum_types(i->first, *corpus());
 	if (!enums)
 	  continue;
 
@@ -4694,7 +4384,7 @@ public:
   bool
   symbol_already_belongs_to_a_function(elf_symbol_sptr& fn)
   {
-    corpus_sptr corp = current_corpus();
+    corpus_sptr corp = corpus();
     if (!corp)
       return false;
 
@@ -4732,7 +4422,7 @@ public:
   void
   fixup_functions_with_no_symbols()
   {
-    corpus_sptr corp = current_corpus();
+    corpus_sptr corp = corpus();
     if (!corp)
       return;
 
@@ -4816,7 +4506,7 @@ public:
 
   /// Canonicalize types which DIE offsets are stored in vectors on
   /// the side.  This is a sub-routine of
-  /// read_context::perform_late_type_canonicalizing().
+  /// reader::perform_late_type_canonicalizing().
   ///
   /// @param source where the DIE of the types to canonicalize are
   /// from.
@@ -4827,9 +4517,9 @@ public:
     if (do_log())
       {
 	cerr << "going to canonicalize types";
-	corpus_sptr c = current_corpus();
+	corpus_sptr c = corpus();
 	if (c)
-	  cerr << " of corpus " << current_corpus()->get_path();
+	  cerr << " of corpus " << corpus()->get_path();
 	cn_timer.start();
       }
 
@@ -4850,7 +4540,7 @@ public:
 		cerr << "canonicalizing type "
 		     << get_pretty_representation(*it, false)
 		     << " [" << i << "/" << total << "]";
-		if (corpus_sptr c = current_corpus())
+		if (corpus_sptr c = corpus())
 		  cerr << "@" << c->get_path();
 		cerr << " ...";
 		single_type_cn_timer.start();
@@ -4870,9 +4560,9 @@ public:
       {
 	cn_timer.stop();
 	cerr << "finished canonicalizing types";
-	corpus_sptr c = current_corpus();
+	corpus_sptr c = corpus();
 	if (c)
-	  cerr << " of corpus " << current_corpus()->get_path();
+	  cerr << " of corpus " << corpus()->get_path();
 	cerr << ": (" << cn_timer << ")\n";
       }
   }
@@ -4948,7 +4638,7 @@ public:
   /// @return the map.
   const tu_die_imported_unit_points_map_type&
   tu_die_imported_unit_points_map(die_source source) const
-  {return const_cast<read_context*>(this)->tu_die_imported_unit_points_map(source);}
+  {return const_cast<reader*>(this)->tu_die_imported_unit_points_map(source);}
 
   /// Getter for the map that associates a translation unit DIE to the
   /// vector of imported unit points that it contains.
@@ -4975,127 +4665,12 @@ public:
     return tu_die_imported_unit_points_map_;
   }
 
-  /// Getter of the current corpus being constructed.
-  ///
-  /// @return the current corpus.
-  const corpus_sptr
-  current_corpus() const
-  {return cur_corpus_;}
-
-  /// Getter of the current corpus being constructed.
-  ///
-  /// @return the current corpus.
-  corpus_sptr
-  current_corpus()
-  {return cur_corpus_;}
-
-  /// Setter of the current corpus being constructed.
-  ///
-  /// @param c the new corpus.
-  void
-  current_corpus(const corpus_sptr& c)
-  {
-    if (c)
-      cur_corpus_ = c;
-  }
-
   /// Reset the current corpus being constructed.
   ///
   /// This actually deletes the current corpus being constructed.
   void
-  reset_current_corpus()
-  {cur_corpus_.reset();}
-
-  /// Getter of the current corpus group being constructed.
-  ///
-  /// @return current the current corpus being constructed, if any, or
-  /// nil.
-  const corpus_group_sptr
-  current_corpus_group() const
-  {return cur_corpus_group_;}
-
-  /// Getter of the current corpus group being constructed.
-  ///
-  /// @return current the current corpus being constructed, if any, or
-  /// nil.
-  corpus_group_sptr
-  current_corpus_group()
-  {return cur_corpus_group_;}
-
-  /// Setter of the current corpus group being constructed.
-  ///
-  /// @param g the new corpus group.
-  void
-  current_corpus_group(const corpus_group_sptr& g)
-  {
-    if (g)
-      cur_corpus_group_ = g;
-  }
-
-  /// Test if there is a corpus group being built.
-  ///
-  /// @return if there is a corpus group being built, false otherwise.
-  bool
-  has_corpus_group() const
-  {return bool(cur_corpus_group_);}
-
-  /// Return the main corpus from the current corpus group, if any.
-  ///
-  /// @return the main corpus of the current corpus group, if any, nil
-  /// if no corpus group is being constructed.
-  corpus_sptr
-  main_corpus_from_current_group()
-  {
-    if (cur_corpus_group_)
-      return cur_corpus_group_->get_main_corpus();
-    return corpus_sptr();
-  }
-
-  /// Return the main corpus from the current corpus group, if any.
-  ///
-  /// @return the main corpus of the current corpus group, if any, nil
-  /// if no corpus group is being constructed.
-  const corpus_sptr
-  main_corpus_from_current_group() const
-  {return const_cast<read_context*>(this)->main_corpus_from_current_group();}
-
-  /// Test if the current corpus being built is the main corpus of the
-  /// current corpus group.
-  ///
-  /// @return return true iff the current corpus being built is the
-  /// main corpus of the current corpus group.
-  bool
-  current_corpus_is_main_corpus_from_current_group() const
-  {
-    corpus_sptr main_corpus = main_corpus_from_current_group();
-
-    if (main_corpus && main_corpus.get() == cur_corpus_.get())
-      return true;
-
-    return false;
-  }
-
-  /// Return true if the current corpus is part of a corpus group
-  /// being built and if it's not the main corpus of the group.
-  ///
-  /// For instance, this would return true if we are loading a linux
-  /// kernel *module* that is part of the current corpus group that is
-  /// being built.  In this case, it means we should re-use types
-  /// coming from the "vmlinux" binary that is the main corpus of the
-  /// group.
-  ///
-  /// @return the corpus group the current corpus belongs to, if the
-  /// current corpus is part of a corpus group being built. Nil otherwise.
-  corpus_sptr
-  should_reuse_type_from_corpus_group() const
-  {
-    if (has_corpus_group() && is_c_language(cur_transl_unit()->get_language()))
-      if (corpus_sptr main_corpus = main_corpus_from_current_group())
-	if (!current_corpus_is_main_corpus_from_current_group())
-	  return current_corpus_group();
-
-    return corpus_sptr();
-  }
+  reset_corpus()
+  {corpus().reset();}
 
   /// Get the map that associates each DIE to its parent DIE.  This is
   /// for DIEs coming from the main debug info sections.
@@ -5105,7 +4680,7 @@ public:
   /// @return the DIE -> parent map.
   const offset_offset_map_type&
   die_parent_map(die_source source) const
-  {return const_cast<read_context*>(this)->die_parent_map(source);}
+  {return const_cast<reader*>(this)->die_parent_map(source);}
 
   /// Get the map that associates each DIE to its parent DIE.  This is
   /// for DIEs coming from the main debug info sections.
@@ -5210,11 +4785,7 @@ public:
   /// @return the symbol table section if found
   Elf_Scn*
   find_symbol_table_section() const
-  {
-    if (!symtab_section_)
-      symtab_section_ = elf_helpers::find_symbol_table_section(elf_handle());
-    return symtab_section_;
-  }
+  {return find_symbol_table_section();}
 
   /// Lookup an elf symbol, referred to by its index, from the .symtab
   /// section.
@@ -5245,70 +4816,6 @@ public:
     return true;
   }
 
-  /// Test if a given function symbol has been exported.
-  ///
-  /// @param symbol_address the address of the symbol we are looking
-  /// for.  Note that this address must be a relative offset from the
-  /// beginning of the .text section, just like the kind of addresses
-  /// that are present in the .symtab section.
-  ///
-  /// @returnthe elf symbol if found, or nil otherwise.
-  elf_symbol_sptr
-  function_symbol_is_exported(GElf_Addr symbol_address) const
-  {
-    elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
-    if (!symbol)
-      return symbol;
-
-    if (!symbol->is_function() || !symbol->is_public())
-      return elf_symbol_sptr();
-
-    address_set_sptr set;
-    bool looking_at_linux_kernel_binary =
-      load_in_linux_kernel_mode() && is_linux_kernel(elf_handle());
-
-    if (looking_at_linux_kernel_binary)
-      {
-	if (symbol->is_in_ksymtab())
-	  return symbol;
-	return elf_symbol_sptr();
-      }
-
-    return symbol;
-  }
-
-  /// Test if a given variable symbol has been exported.
-  ///
-  /// @param symbol_address the address of the symbol we are looking
-  /// for.  Note that this address must be a relative offset from the
-  /// beginning of the .text section, just like the kind of addresses
-  /// that are present in the .symtab section.
-  ///
-  /// @returnthe elf symbol if found, or nil otherwise.
-  elf_symbol_sptr
-  variable_symbol_is_exported(GElf_Addr symbol_address) const
-  {
-    elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
-    if (!symbol)
-      return symbol;
-
-    if (!symbol->is_variable() || !symbol->is_public())
-      return elf_symbol_sptr();
-
-    address_set_sptr set;
-    bool looking_at_linux_kernel_binary =
-      load_in_linux_kernel_mode() && is_linux_kernel(elf_handle());
-
-    if (looking_at_linux_kernel_binary)
-      {
-	if (symbol->is_in_ksymtab())
-	  return symbol;
-	return elf_symbol_sptr();
-      }
-
-    return symbol;
-  }
-
   /// Test if a DIE represents a decl (function or variable) that has
   /// a symbol that is exported, whatever that means.  This is
   /// supposed to work for Linux Kernel binaries as well.
@@ -5347,94 +4854,6 @@ public:
     return result;
   }
 
-  /// Getter for the symtab reader. Will load the symtab from the elf handle if
-  /// not yet set.
-  ///
-  /// @return a shared pointer to the symtab object
-  const symtab_reader::symtab_sptr&
-  symtab() const
-  {
-    if (!symtab_)
-      symtab_ = symtab_reader::symtab::load
-	(elf_handle(), options_.env,
-	 [&](const elf_symbol_sptr& symbol)
-	 {return is_elf_symbol_suppressed(symbol);});
-
-    if (!symtab_)
-      std::cerr << "Symbol table of '" << elf_path_
-		<< "' could not be loaded\n";
-    return symtab_;
-  }
-
-  /// Getter for the ELF dt_needed tag.
-  const vector<string>&
-  dt_needed() const
-  {return dt_needed_;}
-
-  /// Getter for the ELF dt_soname tag.
-  const string&
-  dt_soname() const
-  {return dt_soname_;}
-
-  /// Getter for the ELF architecture of the current file.
-  const string&
-  elf_architecture() const
-  {return elf_architecture_;}
-
-  /// Test if a given ELF symbol was suppressed by a suppression
-  /// specification.
-  ///
-  /// @param symbol the ELF symbol to consider.
-  ///
-  /// @return true iff @p symbol is suppressed.
-  bool
-  is_elf_symbol_suppressed(const elf_symbol_sptr& symbol) const
-  {
-    return (symbol
-	    && suppr::is_elf_symbol_suppressed(*this,
-					       symbol->get_name(),
-					       symbol->get_type()));
-  }
-
-  /// Load the DT_NEEDED and DT_SONAME elf TAGS.
-  ///
-  void
-  load_dt_soname_and_needed()
-  {
-    lookup_data_tag_from_dynamic_segment(elf_handle(), DT_NEEDED, dt_needed_);
-
-    vector<string> dt_tag_data;
-    lookup_data_tag_from_dynamic_segment(elf_handle(), DT_SONAME, dt_tag_data);
-    if (!dt_tag_data.empty())
-      dt_soname_ = dt_tag_data[0];
-  }
-
-  /// Read the string representing the architecture of the current ELF
-  /// file.
-  void
-  load_elf_architecture()
-  {
-    if (!elf_handle())
-      return;
-
-    GElf_Ehdr eh_mem;
-    GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
-
-    elf_architecture_ = e_machine_to_string(elf_header->e_machine);
-  }
-
-  /// Load various ELF data.
-  ///
-  /// This function loads ELF data that are not symbol maps or debug
-  /// info.  That is, things like various tags, elf architecture and
-  /// so on.
-  void
-  load_elf_properties()
-  {
-    load_dt_soname_and_needed();
-    load_elf_architecture();
-  }
-
   /// This is a sub-routine of maybe_adjust_fn_sym_address and
   /// maybe_adjust_var_sym_address.
   ///
@@ -5660,150 +5079,13 @@ public:
   get_variable_address(const Dwarf_Die* variable_die,
 		       Dwarf_Addr&	address) const
   {
-    bool is_tls_address = false;
-    if (!die_location_address(const_cast<Dwarf_Die*>(variable_die),
-			      address, is_tls_address))
-      return false;
-    if (!is_tls_address)
-      address = maybe_adjust_var_sym_address(address);
-    return true;
-  }
-
-  /// Tests if a suppression specification can match ABI artifacts
-  /// coming from the binary being analyzed.
-  ///
-  /// This tests if the suppression can match the soname of and binary
-  /// name of the ELF binary being analyzed.  More precisely, if there
-  /// are any soname or file name property in the suppression and if
-  /// those do *NOT* match the current binary, then the function
-  /// returns false.
-  ///
-  /// @param s the suppression specification to consider.
-  ///
-  /// @return true iff either there are no soname/filename related
-  /// property on the suppression, or if none of the soname/filename
-  /// properties of the suppression match the current binary.
-  bool
-  suppression_can_match(const suppr::suppression_base& s) const
-  {
-    if (!s.priv_->matches_soname(dt_soname()))
-      if (s.has_soname_related_property())
-	// The suppression has some SONAME related properties, but
-	// none of them match the SONAME of the current binary.  So
-	// the suppression cannot match the current binary.
-	return false;
-
-    if (!s.priv_->matches_binary_name(elf_path()))
-      if (s.has_file_name_related_property())
-	// The suppression has some file_name related properties, but
-	// none of them match the file name of the current binary.  So
-	// the suppression cannot match the current binary.
-	return false;
-
-    return true;
-  }
-
-  /// Test whether if a given function suppression matches a function
-  /// designated by a regular expression that describes its linkage
-  /// name (symbol name).
-  ///
-  /// @param s the suppression specification to evaluate to see if it
-  /// matches a given function linkage name
-  ///
-  /// @param fn_linkage_name the linkage name of the function of interest.
-  ///
-  /// @return true iff the suppression specification @p s matches the
-  /// function whose linkage name is @p fn_linkage_name.
-  bool
-  suppression_matches_function_sym_name(const suppr::function_suppression& s,
-					const string& fn_linkage_name) const
-  {
-    if (!suppression_can_match(s))
-      return false;
-
-    return suppr::suppression_matches_function_sym_name(s, fn_linkage_name);
-  }
-
-  /// Test whether if a given function suppression matches a function
-  /// designated by a regular expression that describes its name.
-  ///
-  /// @param s the suppression specification to evaluate to see if it
-  /// matches a given function name.
-  ///
-  /// @param fn_name the name of the function of interest.  Note that
-  /// this name must be *non* qualified.
-  ///
-  /// @return true iff the suppression specification @p s matches the
-  /// function whose name is @p fn_name.
-  bool
-  suppression_matches_function_name(const suppr::function_suppression& s,
-				    const string& fn_name) const
-  {
-    if (!suppression_can_match(s))
-      return false;
-
-    return suppr::suppression_matches_function_name(s, fn_name);
-  }
-
-  /// Test whether if a given variable suppression specification
-  /// matches a variable denoted by its name.
-  ///
-  /// @param s the variable suppression specification to consider.
-  ///
-  /// @param var_name the name of the variable to consider.
-  ///
-  /// @return true iff the suppression specification @p s matches the
-  /// variable whose name is @p var_name.
-  bool
-  suppression_matches_variable_name(const suppr::variable_suppression& s,
-				    const string& var_name) const
-  {
-    if (!suppression_can_match(s))
-      return false;
-
-    return suppr::suppression_matches_variable_name(s, var_name);
-  }
-
-  /// Test whether if a given variable suppression specification
-  /// matches a variable denoted by its linkage name.
-  ///
-  /// @param s the variable suppression specification to consider.
-  ///
-  /// @param var_linkage_name the linkage name of the variable to consider.
-  ///
-  /// @return true iff variable suppression specification @p s matches
-  /// the variable denoted by linkage name @p var_linkage_name.
-  bool
-  suppression_matches_variable_sym_name(const suppr::variable_suppression& s,
-					const string& var_linkage_name) const
-  {
-    if (!suppression_can_match(s))
-      return false;
-
-    return suppr::suppression_matches_variable_sym_name(s, var_linkage_name);
-  }
-
-  /// Test if a given type suppression specification matches a type
-  /// designated by its name and location.
-  ///
-  /// @param s the suppression specification to consider.
-  ///
-  /// @param type_name the fully qualified type name to consider.
-  ///
-  /// @param type_location the type location to consider.
-  ///
-  /// @return true iff the type suppression specification matches a
-  /// type of a given name and location.
-  bool
-  suppression_matches_type_name_or_location(const suppr::type_suppression& s,
-					    const string& type_name,
-					    const location& type_location) const
-  {
-    if (!suppression_can_match(s))
+    bool is_tls_address = false;
+    if (!die_location_address(const_cast<Dwarf_Die*>(variable_die),
+			      address, is_tls_address))
       return false;
-
-    return suppr::suppression_matches_type_name_or_location(s, type_name,
-							    type_location);
+    if (!is_tls_address)
+      address = maybe_adjust_var_sym_address(address);
+    return true;
   }
 
   /// Getter of the exported decls builder object.
@@ -5811,17 +5093,7 @@ public:
   /// @return the exported decls builder.
   corpus::exported_decls_builder*
   exported_decls_builder()
-  {return exported_decls_builder_;}
-
-  /// Setter of the exported decls builder object.
-  ///
-  /// Note that this @ref read_context is not responsible for the live
-  /// time of the exported_decls_builder object.  The corpus is.
-  ///
-  /// @param b the new builder.
-  void
-  exported_decls_builder(corpus::exported_decls_builder* b)
-  {exported_decls_builder_ = b;}
+  {return corpus()->get_exported_decls_builder().get();}
 
   /// Getter of the "load_all_types" flag.  This flag tells if all the
   /// types (including those not reachable by public declarations) are
@@ -5830,7 +5102,7 @@ public:
   /// @return the load_all_types flag.
   bool
   load_all_types() const
-  {return options_.load_all_types;}
+  {return options().load_all_types;}
 
   /// Setter of the "load_all_types" flag.  This flag tells if all the
   /// types (including those not reachable by public declarations) are
@@ -5839,15 +5111,15 @@ public:
   /// @param f the new load_all_types flag.
   void
   load_all_types(bool f)
-  {options_.load_all_types = f;}
+  {options().load_all_types = f;}
 
   bool
   load_in_linux_kernel_mode() const
-  {return options_.load_in_linux_kernel_mode;}
+  {return options().load_in_linux_kernel_mode;}
 
   void
   load_in_linux_kernel_mode(bool f)
-  {options_.load_in_linux_kernel_mode = f;}
+  {options().load_in_linux_kernel_mode = f;}
 
   /// Getter of the "show_stats" flag.
   ///
@@ -5857,7 +5129,7 @@ public:
   /// @return the value of the flag.
   bool
   show_stats() const
-  {return options_.show_stats;}
+  {return options().show_stats;}
 
   /// Setter of the "show_stats" flag.
   ///
@@ -5867,7 +5139,7 @@ public:
   /// @param f the value of the flag.
   void
   show_stats(bool f)
-  {options_.show_stats = f;}
+  {options().show_stats = f;}
 
   /// Getter of the "do_log" flag.
   ///
@@ -5877,7 +5149,7 @@ public:
   /// return the "do_log" flag.
   bool
   do_log() const
-  {return options_.do_log;}
+  {return options().do_log;}
 
   /// Setter of the "do_log" flag.
   ///
@@ -5886,35 +5158,7 @@ public:
   /// @param f the new value of the flag.
   void
   do_log(bool f)
-  {options_.do_log = f;}
-
-  /// If a given function decl is suitable for the set of exported
-  /// functions of the current corpus, this function adds it to that
-  /// set.
-  ///
-  /// @param fn the function to consider for inclusion into the set of
-  /// exported functions of the current corpus.
-  void
-  maybe_add_fn_to_exported_decls(function_decl* fn)
-  {
-    if (fn)
-      if (corpus::exported_decls_builder* b = exported_decls_builder())
-	b->maybe_add_fn_to_exported_fns(fn);
-  }
-
-  /// If a given variable decl is suitable for the set of exported
-  /// variables of the current corpus, this variable adds it to that
-  /// set.
-  ///
-  /// @param fn the variable to consider for inclusion into the set of
-  /// exported variables of the current corpus.
-  void
-  maybe_add_var_to_exported_decls(var_decl* var)
-  {
-    if (var)
-      if (corpus::exported_decls_builder* b = exported_decls_builder())
-	b->maybe_add_var_to_exported_vars(var);
-  }
+  {options().do_log = f;}
 
   /// Walk the DIEs under a given die and for each child, populate the
   /// die -> parent map to record the child -> parent relationship
@@ -6047,13 +5291,15 @@ public:
     // the global namespace so we don't need to build the DIE ->
     // parent map.  So we dont build it in that case.
     for (Dwarf_Off offset = 0, next_offset = 0;
-	 (dwarf_next_unit(dwarf(), offset, &next_offset, &header_size,
+	 (dwarf_next_unit(const_cast<Dwarf*>(dwarf_debug_info()),
+			  offset, &next_offset, &header_size,
 			  NULL, NULL, &address_size, NULL, NULL, NULL) == 0);
 	 offset = next_offset)
       {
 	Dwarf_Off die_offset = offset + header_size;
 	Dwarf_Die cu;
-	if (!dwarf_offdie(dwarf(), die_offset, &cu))
+	if (!dwarf_offdie(const_cast<Dwarf*>(dwarf_debug_info()),
+			  die_offset, &cu))
 	  continue;
 
 	uint64_t l = 0;
@@ -6070,13 +5316,15 @@ public:
     // .debug_info section in the alternate debug info file.
     die_source source = ALT_DEBUG_INFO_DIE_SOURCE;
     for (Dwarf_Off offset = 0, next_offset = 0;
-	 (dwarf_next_unit(alt_dwarf(), offset, &next_offset, &header_size,
+	 (dwarf_next_unit(const_cast<Dwarf*>(alternate_dwarf_debug_info()),
+			  offset, &next_offset, &header_size,
 			  NULL, NULL, &address_size, NULL, NULL, NULL) == 0);
 	 offset = next_offset)
       {
 	Dwarf_Off die_offset = offset + header_size;
 	Dwarf_Die cu;
-	if (!dwarf_offdie(alt_dwarf(), die_offset, &cu))
+	if (!dwarf_offdie(const_cast<Dwarf*>(alternate_dwarf_debug_info()),
+			  die_offset, &cu))
 	  continue;
 	cur_tu_die(&cu);
 
@@ -6092,13 +5340,15 @@ public:
     address_size = 0;
     header_size = 0;
     for (Dwarf_Off offset = 0, next_offset = 0;
-	 (dwarf_next_unit(dwarf(), offset, &next_offset, &header_size,
+	 (dwarf_next_unit(const_cast<Dwarf*>(dwarf_debug_info()),
+			  offset, &next_offset, &header_size,
 			  NULL, NULL, &address_size, NULL, NULL, NULL) == 0);
 	 offset = next_offset)
       {
 	Dwarf_Off die_offset = offset + header_size;
 	Dwarf_Die cu;
-	if (!dwarf_offdie(dwarf(), die_offset, &cu))
+	if (!dwarf_offdie(const_cast<Dwarf*>(dwarf_debug_info()),
+			  die_offset, &cu))
 	  continue;
 	cur_tu_die(&cu);
 	imported_unit_points_type& imported_units =
@@ -6115,7 +5365,8 @@ public:
     uint64_t type_signature = 0;
     Dwarf_Off type_offset;
     for (Dwarf_Off offset = 0, next_offset = 0;
-	 (dwarf_next_unit(dwarf(), offset, &next_offset, &header_size,
+	 (dwarf_next_unit(const_cast<Dwarf*>(dwarf_debug_info()),
+			  offset, &next_offset, &header_size,
 			  NULL, NULL, &address_size, NULL,
 			  &type_signature, &type_offset) == 0);
 	 offset = next_offset)
@@ -6123,7 +5374,8 @@ public:
 	Dwarf_Off die_offset = offset + header_size;
 	Dwarf_Die cu;
 
-	if (!dwarf_offdie_types(dwarf(), die_offset, &cu))
+	if (!dwarf_offdie_types(const_cast<Dwarf*>(dwarf_debug_info()),
+				die_offset, &cu))
 	  continue;
 	cur_tu_die(&cu);
 	imported_unit_points_type& imported_units =
@@ -6132,7 +5384,7 @@ public:
 	build_die_parent_relations_under(&cu, source, imported_units);
       }
   }
-};// end class read_context.
+};// end class reader.
 
 /// The type of the aggregates being compared during a DIE comparison.
 ///
@@ -6146,8 +5398,8 @@ public:
 /// that takes place during the canonicalization
 struct offset_pairs_stack_type
 {
-  // The DWARF read context that is useful for so many things.
-  const read_context& ctxt_;
+  // The DWARF DWARF reader that is useful for so many things.
+  const reader& rdr_;
   // The set of types that are being compared.  This is to speed up
   // searches.
   offset_pair_set_type set_;
@@ -6161,8 +5413,8 @@ struct offset_pairs_stack_type
   // types it depends on.
   offset_pair_vect_map_type dependant_types_;
 
-  offset_pairs_stack_type(const read_context& ctxt)
-    : ctxt_ (ctxt)
+  offset_pairs_stack_type(const reader& rdr)
+    : rdr_ (rdr)
   {}
 
   /// Add a pair of types being compared to the stack of aggregates
@@ -6377,13 +5629,13 @@ struct offset_pairs_stack_type
 	    if (dependant_types_it->second.empty())
 	      {
 		if (erase_cached_results)
-		  ctxt_.die_comparison_results_.erase(dependant_type);
+		  rdr_.die_comparison_results_.erase(dependant_type);
 		dependant_types_.erase(dependant_types_it);
 	      }
 	  }
       }
     if (erase_cached_results)
-      ctxt_.die_comparison_results_.erase(p);
+      rdr_.die_comparison_results_.erase(p);
     redundant_types_.erase(p);
   }
 
@@ -6414,32 +5666,32 @@ struct offset_pairs_stack_type
       {
 	// If this dependant type was canonical-type-propagated then
 	// erase that canonical type.
-	if (ctxt_.propagated_types_.find(dependant_type)
-	    != ctxt_.propagated_types_.end())
+	if (rdr_.propagated_types_.find(dependant_type)
+	    != rdr_.propagated_types_.end())
 	  {
-	    ctxt_.erase_canonical_die_offset(dependant_type.first.offset_,
+	    rdr_.erase_canonical_die_offset(dependant_type.first.offset_,
 					     dependant_type.first.source_,
 					     /*die_as_type=*/true);
-	    ctxt_.propagated_types_.erase(dependant_type);
-	    ctxt_.cancelled_propagation_count_++;
+	    rdr_.propagated_types_.erase(dependant_type);
+	    rdr_.cancelled_propagation_count_++;
 	  }
 	// Update the cached result.  We know the comparison result
 	// must now be different.
-	auto comp_result_it = ctxt_.die_comparison_results_.find(p);
-	if (comp_result_it != ctxt_.die_comparison_results_.end())
+	auto comp_result_it = rdr_.die_comparison_results_.find(p);
+	if (comp_result_it != rdr_.die_comparison_results_.end())
 	  {
 	    ABG_ASSERT(comp_result_it->second == COMPARISON_RESULT_UNKNOWN);
 	    comp_result_it->second= COMPARISON_RESULT_DIFFERENT;
 	  }
       }
 
-    if (ctxt_.propagated_types_.find(p) != ctxt_.propagated_types_.end())
+    if (rdr_.propagated_types_.find(p) != rdr_.propagated_types_.end())
       {
-	ctxt_.erase_canonical_die_offset(p.first.offset_,
+	rdr_.erase_canonical_die_offset(p.first.offset_,
 					 p.first.source_,
 					 /*die_as_type=*/true);
-	ctxt_.propagated_types_.erase(p);
-	ctxt_.cancelled_propagation_count_++;
+	rdr_.propagated_types_.erase(p);
+	rdr_.cancelled_propagation_count_++;
       }
   }
 
@@ -6477,7 +5729,7 @@ struct offset_pairs_stack_type
 }; // end struct offset_pairs_stack_type
 
 static type_or_decl_base_sptr
-build_ir_node_from_die(read_context&	ctxt,
+build_ir_node_from_die(reader&	rdr,
 		       Dwarf_Die*	die,
 		       scope_decl*	scope,
 		       bool		called_from_public_decl,
@@ -6486,13 +5738,13 @@ build_ir_node_from_die(read_context&	ctxt,
 		       bool		is_required_decl_spec = false);
 
 static type_or_decl_base_sptr
-build_ir_node_from_die(read_context&	ctxt,
+build_ir_node_from_die(reader&	rdr,
 		       Dwarf_Die*	die,
 		       bool		called_from_public_decl,
 		       size_t		where_offset);
 
 static class_decl_sptr
-add_or_update_class_type(read_context&	 ctxt,
+add_or_update_class_type(reader&	 rdr,
 			 Dwarf_Die*	 die,
 			 scope_decl*	 scope,
 			 bool		 is_struct,
@@ -6502,7 +5754,7 @@ add_or_update_class_type(read_context&	 ctxt,
 			 bool		 is_declaration_only);
 
 static union_decl_sptr
-add_or_update_union_type(read_context&	 ctxt,
+add_or_update_union_type(reader&	 rdr,
 			 Dwarf_Die*	 die,
 			 scope_decl*	 scope,
 			 union_decl_sptr union_type,
@@ -6511,25 +5763,25 @@ add_or_update_union_type(read_context&	 ctxt,
 			 bool		 is_declaration_only);
 
 static decl_base_sptr
-build_ir_node_for_void_type(read_context& ctxt);
+build_ir_node_for_void_type(reader& rdr);
 
 static decl_base_sptr
-build_ir_node_for_variadic_parameter_type(read_context &ctxt);
+build_ir_node_for_variadic_parameter_type(reader &rdr);
 
 static function_decl_sptr
-build_function_decl(read_context&	ctxt,
+build_function_decl(reader&	rdr,
 		    Dwarf_Die*		die,
 		    size_t		where_offset,
 		    function_decl_sptr	fn);
 
 static bool
-function_is_suppressed(const read_context& ctxt,
+function_is_suppressed(const reader& rdr,
 		       const scope_decl* scope,
 		       Dwarf_Die *function_die,
 		       bool is_declaration_only);
 
 static function_decl_sptr
-build_or_get_fn_decl_if_not_suppressed(read_context&	ctxt,
+build_or_get_fn_decl_if_not_suppressed(reader&	rdr,
 				       scope_decl	*scope,
 				       Dwarf_Die	*die,
 				       size_t	where_offset,
@@ -6537,20 +5789,20 @@ build_or_get_fn_decl_if_not_suppressed(read_context&	ctxt,
 				       function_decl_sptr f);
 
 static var_decl_sptr
-build_var_decl(read_context&	ctxt,
+build_var_decl(reader&	rdr,
 	       Dwarf_Die	*die,
 	       size_t		where_offset,
 	       var_decl_sptr	result = var_decl_sptr());
 
 static var_decl_sptr
-build_or_get_var_decl_if_not_suppressed(read_context&	ctxt,
+build_or_get_var_decl_if_not_suppressed(reader&	rdr,
 					scope_decl	*scope,
 					Dwarf_Die	*die,
 					size_t	where_offset,
 					var_decl_sptr	res = var_decl_sptr(),
 					bool is_required_decl_spec = false);
 static bool
-variable_is_suppressed(const read_context& ctxt,
+variable_is_suppressed(const reader& rdr,
 		       const scope_decl* scope,
 		       Dwarf_Die *variable_die,
 		       bool is_required_decl_spec = false);
@@ -6559,78 +5811,7 @@ static void
 finish_member_function_reading(Dwarf_Die*			die,
 			       const function_decl_sptr&	f,
 			       const class_or_union_sptr	klass,
-			       read_context&			ctxt);
-
-/// Setter of the debug info root path for a dwarf reader context.
-///
-/// @param ctxt the dwarf reader context to consider.
-///
-/// @param path the new debug info root path.  This must be a pointer to a
-/// character string which life time should be greater than the life
-/// time of the read context.
-void
-set_debug_info_root_path(read_context& ctxt, char** path)
-{ctxt.offline_callbacks()->debuginfo_path = path;}
-
-/// Setter of the debug info root path for a dwarf reader context.
-///
-/// @param ctxt the dwarf reader context to consider.
-///
-/// @return a pointer to the debug info root path.
-///
-/// time of the read context.
-char**
-get_debug_info_root_path(read_context& ctxt)
-{return ctxt.offline_callbacks()->debuginfo_path;}
-
-/// Getter of the "show_stats" flag.
-///
-/// This flag tells if we should emit statistics about various
-/// internal stuff.
-///
-/// @param ctx the read context to consider for this flag.
-///
-/// @return the value of the flag.
-bool
-get_show_stats(read_context& ctxt)
-{return ctxt.show_stats();}
-
-/// Setter of the "show_stats" flag.
-///
-/// This flag tells if we should emit statistics about various
-/// internal stuff.
-///
-/// @param ctxt the read context to consider for this flag.
-///
-/// @param f the value of the flag.
-void
-set_show_stats(read_context& ctxt, bool f)
-{ctxt.show_stats(f);}
-
-/// Setter of the "drop_undefined_syms" flag.
-///
-/// This flag tells if we should drop functions or variables
-/// with undefined symbols.
-///
-/// @param ctxt the read context to consider for this flag.
-///
-/// @param f the value of the flag.
-void
-set_drop_undefined_syms(read_context& ctxt, bool f)
-{ctxt.drop_undefined_syms(f);}
-
-/// Setter of the "do_log" flag.
-///
-/// This flag tells if we should emit verbose logs for various
-/// internal things related to DWARF reading.
-///
-/// @param ctxt the DWARF reading context to consider.
-///
-/// @param f the new value of the flag.
-void
-set_do_log(read_context& ctxt, bool f)
-{ctxt.do_log(f);}
-
+			       reader&			rdr);
 
 /// Test if a given DIE is anonymous
 ///
@@ -6980,13 +6161,13 @@ die_address_attribute(Dwarf_Die* die, unsigned attr_name, Dwarf_Addr& result)
 
 /// Returns the source location associated with a decl DIE.
 ///
-/// @param ctxt the @ref read_context to use.
+/// @param rdr the @ref reader to use.
 ///
 /// @param die the DIE the read the source location from.
 ///
 /// @return the location associated with @p die.
 static location
-die_location(const read_context& ctxt, const Dwarf_Die* die)
+die_location(const reader& rdr, const Dwarf_Die* die)
 {
   if (!die)
     return location();
@@ -6997,7 +6178,7 @@ die_location(const read_context& ctxt, const Dwarf_Die* die)
 
   if (!file.empty() && line != 0)
     {
-      translation_unit_sptr tu = ctxt.cur_transl_unit();
+      translation_unit_sptr tu = rdr.cur_transl_unit();
       location l = tu->get_loc_mgr().create_new_location(file, line, 1);
       return l;
     }
@@ -7018,7 +6199,7 @@ die_name(const Dwarf_Die* die)
 
 /// Return the location, the name and the mangled name of a given DIE.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @param die the DIE to read location and names from.
 ///
@@ -7028,13 +6209,13 @@ die_name(const Dwarf_Die* die)
 ///
 /// @param linkage_name the linkage_name output parameter to set.
 static void
-die_loc_and_name(const read_context&	ctxt,
+die_loc_and_name(const reader&	rdr,
 		 Dwarf_Die*		die,
 		 location&		loc,
 		 string&		name,
 		 string&		linkage_name)
 {
-  loc = die_location(ctxt, die);
+  loc = die_location(rdr, die);
   name = die_name(die);
   linkage_name = die_linkage_name(die);
 }
@@ -7150,7 +6331,7 @@ die_is_public_decl(const Dwarf_Die* die)
 /// @return true iff either the DIE is public or is a variable DIE
 /// that is at (global) namespace level.
 static bool
-die_is_effectively_public_decl(const read_context& ctxt,
+die_is_effectively_public_decl(const reader& rdr,
 			       const Dwarf_Die* die)
 {
   if (die_is_public_decl(die))
@@ -7162,7 +6343,7 @@ die_is_effectively_public_decl(const read_context& ctxt,
       // The DIE is a variable.
       Dwarf_Die parent_die;
       size_t where_offset = 0;
-      if (!get_parent_die(ctxt, die, parent_die, where_offset))
+      if (!get_parent_die(rdr, die, parent_die, where_offset))
 	return false;
 
       tag = dwarf_tag(&parent_die);
@@ -7402,7 +6583,7 @@ type_comparison_result_to_be_cached(unsigned tag)
 
 /// Cache the result of comparing to type DIEs.
 ///
-/// @param ctxt the context to consider.
+/// @param rdr the context to consider.
 ///
 /// @param tag the tag of the DIEs to consider.
 ///
@@ -7410,7 +6591,7 @@ type_comparison_result_to_be_cached(unsigned tag)
 ///
 /// @param result the comparison result to be cached.
 static bool
-maybe_cache_type_comparison_result(const read_context& ctxt,
+maybe_cache_type_comparison_result(const reader& rdr,
 				   int tag,
 				   const offset_pair_type& p,
 				   comparison_result result)
@@ -7420,7 +6601,7 @@ maybe_cache_type_comparison_result(const read_context& ctxt,
 	  && result != COMPARISON_RESULT_DIFFERENT))
     return false;
 
-  ctxt.die_comparison_results_[p] = result;
+  rdr.die_comparison_results_[p] = result;
 
   return true;
 
@@ -7428,7 +6609,7 @@ maybe_cache_type_comparison_result(const read_context& ctxt,
 
 /// Get the cached result of the comparison of a pair of DIEs.
 ///
-/// @param ctxt the context to consider.
+/// @param rdr the context to consider.
 ///
 /// @param tag the tag of the pair of DIEs to consider.
 ///
@@ -7440,12 +6621,12 @@ maybe_cache_type_comparison_result(const read_context& ctxt,
 /// @return true iff a cached result for the comparisonof @p has been
 /// found and set into @p result.
 static bool
-get_cached_type_comparison_result(const read_context& ctxt,
+get_cached_type_comparison_result(const reader& rdr,
 				  const offset_pair_type& p,
 				  comparison_result& result)
 {
-  auto i = ctxt.die_comparison_results_.find(p);
-  if (i != ctxt.die_comparison_results_.end())
+  auto i = rdr.die_comparison_results_.find(p);
+  if (i != rdr.die_comparison_results_.end())
     {
       result = i->second;
       return true;
@@ -7456,7 +6637,7 @@ get_cached_type_comparison_result(const read_context& ctxt,
 /// Get the cached result of the comparison of a pair of DIEs, if the
 /// kind of DIEs ought to have its comparison results cached.
 ///
-/// @param ctxt the context to consider.
+/// @param rdr the context to consider.
 ///
 /// @param tag the tag of the pair of DIEs to consider.
 ///
@@ -7468,7 +6649,7 @@ get_cached_type_comparison_result(const read_context& ctxt,
 /// @return true iff a cached result for the comparisonof @p has been
 /// found and set into @p result.
 static bool
-maybe_get_cached_type_comparison_result(const read_context& ctxt,
+maybe_get_cached_type_comparison_result(const reader& rdr,
 					int tag,
 					const offset_pair_type& p,
 					comparison_result& result)
@@ -7478,7 +6659,7 @@ maybe_get_cached_type_comparison_result(const read_context& ctxt,
       // Types of this kind might have their comparison result cached
       // when they are not canonicalized.  So let's see if we have a
       // cached comparison result.
-      if (get_cached_type_comparison_result(ctxt, p, result))
+      if (get_cached_type_comparison_result(rdr, p, result))
 	return true;
     }
   return false;
@@ -7878,7 +7059,7 @@ die_object_pointer_is_for_const_method(Dwarf_Die* die)
 
 /// Test if a DIE represents an entity that is at class scope.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @param die the DIE to consider.
 ///
@@ -7892,12 +7073,12 @@ die_object_pointer_is_for_const_method(Dwarf_Die* die)
 /// class_scope_die is set to the DIE of the class that contains @p
 /// die.
 static bool
-die_is_at_class_scope(const read_context& ctxt,
+die_is_at_class_scope(const reader& rdr,
 		      const Dwarf_Die* die,
 		      size_t where_offset,
 		      Dwarf_Die& class_scope_die)
 {
-  if (!get_scope_die(ctxt, die, where_offset, class_scope_die))
+  if (!get_scope_die(rdr, die, where_offset, class_scope_die))
     return false;
 
   int tag = dwarf_tag(&class_scope_die);
@@ -8028,7 +7209,7 @@ die_peel_pointer_and_typedef(const Dwarf_Die *die, Dwarf_Die& peeled_die)
 
 /// Test if a DIE for a function type represents a method type.
 ///
-/// @param ctxt the read context.
+/// @param rdr the DWARF reader.
 ///
 /// @param die the DIE to consider.
 ///
@@ -8049,7 +7230,7 @@ die_peel_pointer_and_typedef(const Dwarf_Die *die, Dwarf_Die& peeled_die)
 ///
 /// @return true iff @p die is a DIE for a method type.
 static bool
-die_function_type_is_method_type(const read_context& ctxt,
+die_function_type_is_method_type(const reader& rdr,
 				 const Dwarf_Die *die,
 				 size_t where_offset,
 				 Dwarf_Die& object_pointer_die,
@@ -8077,7 +7258,7 @@ die_function_type_is_method_type(const read_context& ctxt,
 	    has_object_pointer = true;
 	  else
 	    {
-	      if (die_is_at_class_scope(ctxt, &spec_or_origin_die,
+	      if (die_is_at_class_scope(rdr, &spec_or_origin_die,
 					where_offset, class_die))
 		is_static = true;
 	      else
@@ -8090,7 +7271,7 @@ die_function_type_is_method_type(const read_context& ctxt,
 	    has_object_pointer = true;
 	  else
 	    {
-	      if (die_is_at_class_scope(ctxt, die, where_offset, class_die))
+	      if (die_is_at_class_scope(rdr, die, where_offset, class_die))
 		is_static = true;
 	      else
 		return false;
@@ -9441,14 +8622,14 @@ die_constant_data_member_location(const Dwarf_Die *die,
 ///     the offset of the function in the vtable.  In this case this
 ///     function returns that constant.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param die the DIE to read the information from.
 ///
 /// @param offset the resulting constant offset, in bits.  This
 /// argument is set iff the function returns true.
 static bool
-die_member_offset(const read_context& ctxt,
+die_member_offset(const reader& rdr,
 		  const Dwarf_Die* die,
 		  int64_t& offset)
 {
@@ -9489,7 +8670,7 @@ die_member_offset(const read_context& ctxt,
 	  bool is_tls_address = false;
 	  if (!eval_last_constant_dwarf_sub_expr(expr, expr_len,
 						 offset, is_tls_address,
-						 ctxt.dwarf_expr_eval_ctxt()))
+						 rdr.dwarf_expr_eval_ctxt()))
 	    return false;
 	}
     }
@@ -9506,7 +8687,7 @@ die_member_offset(const read_context& ctxt,
   // offset of the bitfield data member it describes.  For details
   // about the conversion, please read the extensive comments of
   // read_and_convert_DW_at_bit_offset.
-  bool is_big_endian = architecture_is_big_endian(ctxt.elf_handle());
+  bool is_big_endian = architecture_is_big_endian(rdr.elf_handle());
   if (read_and_convert_DW_at_bit_offset(die, is_big_endian, bit_offset))
     offset += bit_offset;
 
@@ -9725,7 +8906,7 @@ get_internal_anonymous_die_name(Dwarf_Die *die,
 /// For instance, if the DIE tag is DW_TAG_subprogram then this
 /// function computes the name of the function *type*.
 ///
-/// @param ctxt the read context.
+/// @param rdr the DWARF reader.
 ///
 /// @param die the DIE to consider.
 ///
@@ -9734,7 +8915,7 @@ get_internal_anonymous_die_name(Dwarf_Die *die,
 ///
 /// @return a copy of the qualified name of the type.
 static string
-die_qualified_type_name(const read_context& ctxt,
+die_qualified_type_name(const reader& rdr,
 			const Dwarf_Die* die,
 			size_t where_offset)
 {
@@ -9750,10 +8931,10 @@ die_qualified_type_name(const read_context& ctxt,
   string name = die_name(die);
 
   Dwarf_Die scope_die;
-  if (!get_scope_die(ctxt, die, where_offset, scope_die))
+  if (!get_scope_die(rdr, die, where_offset, scope_die))
     return "";
 
-  string parent_name = die_qualified_name(ctxt, &scope_die, where_offset);
+  string parent_name = die_qualified_name(rdr, &scope_die, where_offset);
   bool colon_colon = die_is_type(die) || die_is_namespace(die);
   string separator = colon_colon ? "::" : ".";
 
@@ -9836,7 +9017,7 @@ die_qualified_type_name(const read_context& ctxt,
 	string underlying_type_repr;
 	if (has_underlying_type_die)
 	  underlying_type_repr =
-	    die_qualified_type_name(ctxt, &underlying_type_die, where_offset);
+	    die_qualified_type_name(rdr, &underlying_type_die, where_offset);
 	else
 	  underlying_type_repr = "void";
 
@@ -9869,7 +9050,7 @@ die_qualified_type_name(const read_context& ctxt,
 	  break;
 
 	string pointed_type_repr =
-	  die_qualified_type_name(ctxt, &pointed_to_type_die, where_offset);
+	  die_qualified_type_name(rdr, &pointed_to_type_die, where_offset);
 
 	repr = pointed_type_repr;
 	if (repr.empty())
@@ -9899,7 +9080,7 @@ die_qualified_type_name(const read_context& ctxt,
 	// the ::as_string() method of that type.  So we don't add
 	// that type to the current type tree being built.
 	array_type_def::subrange_sptr s =
-	  build_subrange_type(const_cast<read_context&>(ctxt),
+	  build_subrange_type(const_cast<reader&>(rdr),
 			      die, where_offset,
 			      /*associate_die_to_type=*/false);
 	repr += s->as_string();
@@ -9912,12 +9093,12 @@ die_qualified_type_name(const read_context& ctxt,
 	if (!die_die_attribute(die, DW_AT_type, element_type_die))
 	  break;
 	string element_type_name =
-	  die_qualified_type_name(ctxt, &element_type_die, where_offset);
+	  die_qualified_type_name(rdr, &element_type_die, where_offset);
 	if (element_type_name.empty())
 	  break;
 
 	array_type_def::subranges_type subranges;
-	build_subranges_from_array_type_die(const_cast<read_context&>(ctxt),
+	build_subranges_from_array_type_die(const_cast<reader&>(rdr),
 					    die, subranges, where_offset,
 					    /*associate_type_to_die=*/false);
 
@@ -9935,7 +9116,7 @@ die_qualified_type_name(const read_context& ctxt,
 	bool is_const = false;
 	bool is_static = false;
 
-	die_return_and_parm_names_from_fn_type_die(ctxt, die, where_offset,
+	die_return_and_parm_names_from_fn_type_die(rdr, die, where_offset,
 						   /*pretty_print=*/true,
 						   return_type_name, class_name,
 						   parm_names, is_const,
@@ -9985,7 +9166,7 @@ die_qualified_type_name(const read_context& ctxt,
 /// For instance, for a DIE of tag DW_TAG_subprogram this function
 /// computes the signature of the function *declaration*.
 ///
-/// @param ctxt the read context.
+/// @param rdr the DWARF reader.
 ///
 /// @param die the DIE to consider.
 ///
@@ -9993,7 +9174,7 @@ die_qualified_type_name(const read_context& ctxt,
 ///
 /// @return a copy of the computed name.
 static string
-die_qualified_decl_name(const read_context& ctxt,
+die_qualified_decl_name(const reader& rdr,
 			const Dwarf_Die* die,
 			size_t where_offset)
 {
@@ -10003,10 +9184,10 @@ die_qualified_decl_name(const read_context& ctxt,
   string name = die_name(die);
 
   Dwarf_Die scope_die;
-  if (!get_scope_die(ctxt, die, where_offset, scope_die))
+  if (!get_scope_die(rdr, die, where_offset, scope_die))
     return "";
 
-  string scope_name = die_qualified_name(ctxt, &scope_die, where_offset);
+  string scope_name = die_qualified_name(rdr, &scope_die, where_offset);
   string separator = "::";
 
   string repr;
@@ -10020,7 +9201,7 @@ die_qualified_decl_name(const read_context& ctxt,
       repr = scope_name.empty() ? name : scope_name + separator + name;
       break;
     case DW_TAG_subprogram:
-      repr = die_function_signature(ctxt, die, where_offset);
+      repr = die_function_signature(rdr, die, where_offset);
       break;
 
     case DW_TAG_unspecified_parameters:
@@ -10046,7 +9227,7 @@ die_qualified_decl_name(const read_context& ctxt,
 /// DW_TAG_subprogram is going to be considered as a "type" -- just
 /// like if it was a DW_TAG_subroutine_type.
 ///
-/// @param ctxt the read context.
+/// @param rdr the DWARF reader.
 ///
 /// @param die the DIE to consider.
 ///
@@ -10054,12 +9235,12 @@ die_qualified_decl_name(const read_context& ctxt,
 ///
 /// @return a copy of the computed name.
 static string
-die_qualified_name(const read_context& ctxt, const Dwarf_Die* die, size_t where)
+die_qualified_name(const reader& rdr, const Dwarf_Die* die, size_t where)
 {
   if (die_is_type(die))
-    return die_qualified_type_name(ctxt, die, where);
+    return die_qualified_type_name(rdr, die, where);
   else if (die_is_decl(die))
-    return die_qualified_decl_name(ctxt, die, where);
+    return die_qualified_decl_name(rdr, die, where);
   return "";
 }
 
@@ -10070,7 +9251,7 @@ die_qualified_name(const read_context& ctxt, const Dwarf_Die* die, size_t where)
 /// that tag; or if the DIE's qualified name is built from names of
 /// sub-types DIEs whose tags are not yet supported.
 ///
-/// @param ctxt the reading context.
+/// @param rdr the DWARF reader.
 ///
 /// @param die the DIE to consider.
 ///
@@ -10081,7 +9262,7 @@ die_qualified_name(const read_context& ctxt, const Dwarf_Die* die, size_t where)
 ///
 /// @return true if the qualified name of the DIE is empty.
 static bool
-die_qualified_type_name_empty(const read_context& ctxt,
+die_qualified_type_name_empty(const reader& rdr,
 			      const Dwarf_Die* die,
 			      size_t where, string &qualified_name)
 {
@@ -10104,19 +9285,19 @@ die_qualified_type_name_empty(const read_context& ctxt,
       if (die_die_attribute(die, DW_AT_type, underlying_type_die))
 	{
 	  string name =
-	    die_qualified_type_name(ctxt, &underlying_type_die, where);
+	    die_qualified_type_name(rdr, &underlying_type_die, where);
 	  if (name.empty())
 	    return true;
 	}
     }
   else
     {
-      string name = die_qualified_type_name(ctxt, die, where);
+      string name = die_qualified_type_name(rdr, die, where);
       if (name.empty())
 	return true;
     }
 
-  qname = die_qualified_type_name(ctxt, die, where);
+  qname = die_qualified_type_name(rdr, die, where);
   if (qname.empty())
     return true;
 
@@ -10134,7 +9315,7 @@ die_qualified_type_name_empty(const read_context& ctxt,
 /// When the function we are looking at is a member function, it also
 /// tells if it's const.
 ///
-/// @param ctxt the reading context.
+/// @param rdr the DWARF reader.
 ///
 /// @param die the DIE of the function or function type we are looking
 /// at.
@@ -10160,7 +9341,7 @@ die_qualified_type_name_empty(const read_context& ctxt,
 /// @param is_static out parameter.  If the function is a static
 /// member function, then this is set to true.
 static void
-die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
+die_return_and_parm_names_from_fn_type_die(const reader& rdr,
 					   const Dwarf_Die* die,
 					   size_t where_offset,
 					   bool pretty_print,
@@ -10177,22 +9358,22 @@ die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
   else
     return_type_name =
       pretty_print
-      ? ctxt.get_die_pretty_representation(&ret_type_die, where_offset)
-      : ctxt.get_die_qualified_type_name(&ret_type_die, where_offset);
+      ? rdr.get_die_pretty_representation(&ret_type_die, where_offset)
+      : rdr.get_die_qualified_type_name(&ret_type_die, where_offset);
 
   if (return_type_name.empty())
     return_type_name = "void";
 
   Dwarf_Die object_pointer_die, class_die;
   bool is_method_type =
-    die_function_type_is_method_type(ctxt, die, where_offset,
+    die_function_type_is_method_type(rdr, die, where_offset,
 				     object_pointer_die,
 				     class_die, is_static);
 
   is_const = false;
   if (is_method_type)
     {
-      class_name = ctxt.get_die_qualified_type_name(&class_die, where_offset);
+      class_name = rdr.get_die_qualified_type_name(&class_die, where_offset);
 
       Dwarf_Die this_pointer_die;
       Dwarf_Die pointed_to_die;
@@ -10223,8 +9404,8 @@ die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
 	      continue;
 	    string qualified_name =
 	      pretty_print
-	      ? ctxt.get_die_pretty_representation(&parm_type_die, where_offset)
-	      : ctxt.get_die_qualified_type_name(&parm_type_die, where_offset);
+	      ? rdr.get_die_pretty_representation(&parm_type_die, where_offset)
+	      : rdr.get_die_qualified_type_name(&parm_type_die, where_offset);
 
 	    if (qualified_name.empty())
 	      continue;
@@ -10248,11 +9429,11 @@ die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
   if (class_name.empty())
     {
       Dwarf_Die parent_die;
-      if (get_parent_die(ctxt, die, parent_die, where_offset))
+      if (get_parent_die(rdr, die, parent_die, where_offset))
 	{
 	  if (die_is_class_type(&parent_die))
 	    class_name =
-	      ctxt.get_die_qualified_type_name(&parent_die, where_offset);
+	      rdr.get_die_qualified_type_name(&parent_die, where_offset);
 	}
     }
 }
@@ -10260,7 +9441,7 @@ die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
 /// This computes the signature of the a function declaration
 /// represented by a DIE.
 ///
-/// @param ctxt the reading context.
+/// @param rdr the DWARF reader.
 ///
 /// @param fn_die the DIE of the function to consider.
 ///
@@ -10269,14 +9450,14 @@ die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
 ///
 /// @return a copy of the computed function signature string.
 static string
-die_function_signature(const read_context& ctxt,
+die_function_signature(const reader& rdr,
 		       const Dwarf_Die *fn_die,
 		       size_t where_offset)
 {
 
   translation_unit::language lang;
   bool has_lang = false;
-  if ((has_lang = ctxt.get_die_language(fn_die, lang)))
+  if ((has_lang = rdr.get_die_language(fn_die, lang)))
     {
       // In a binary originating from the C language, it's OK to use
       // the linkage name of the function as a key for the map which
@@ -10299,7 +9480,7 @@ die_function_signature(const read_context& ctxt,
   string return_type_name;
   Dwarf_Die ret_type_die;
   if (die_die_attribute(fn_die, DW_AT_type, ret_type_die))
-    return_type_name = ctxt.get_die_qualified_type_name(&ret_type_die,
+    return_type_name = rdr.get_die_qualified_type_name(&ret_type_die,
 							where_offset);
 
   if (return_type_name.empty())
@@ -10307,8 +9488,8 @@ die_function_signature(const read_context& ctxt,
 
   Dwarf_Die scope_die;
   string scope_name;
-  if (get_scope_die(ctxt, fn_die, where_offset, scope_die))
-    scope_name = ctxt.get_die_qualified_name(&scope_die, where_offset);
+  if (get_scope_die(rdr, fn_die, where_offset, scope_die))
+    scope_name = rdr.get_die_qualified_name(&scope_die, where_offset);
   string fn_name = die_name(fn_die);
   if (!scope_name.empty())
     fn_name  = scope_name + "::" + fn_name;
@@ -10318,7 +9499,7 @@ die_function_signature(const read_context& ctxt,
   bool is_const = false;
   bool is_static = false;
 
-  die_return_and_parm_names_from_fn_type_die(ctxt, fn_die, where_offset,
+  die_return_and_parm_names_from_fn_type_die(rdr, fn_die, where_offset,
 					     /*pretty_print=*/false,
 					     return_type_name, class_name,
 					     parm_names, is_const, is_static);
@@ -10373,7 +9554,7 @@ die_function_signature(const read_context& ctxt,
 /// Note that this function is also used to pretty print functions.
 /// For functions, it prints the *type* of the function.
 ///
-/// @param ctxt the context to use.
+/// @param rdr the context to use.
 ///
 /// @param the DIE of the type to pretty print.
 ///
@@ -10383,7 +9564,7 @@ die_function_signature(const read_context& ctxt,
 ///
 /// @return the resulting pretty representation.
 static string
-die_pretty_print_type(read_context& ctxt,
+die_pretty_print_type(reader& rdr,
 		      const Dwarf_Die* die,
 		      size_t where_offset)
 {
@@ -10413,17 +9594,17 @@ die_pretty_print_type(read_context& ctxt,
       break;
 
     case DW_TAG_namespace:
-      repr = "namespace " + ctxt.get_die_qualified_type_name(die, where_offset);
+      repr = "namespace " + rdr.get_die_qualified_type_name(die, where_offset);
       break;
 
     case DW_TAG_base_type:
-      repr = ctxt.get_die_qualified_type_name(die, where_offset);
+      repr = rdr.get_die_qualified_type_name(die, where_offset);
       break;
 
     case DW_TAG_typedef:
       {
 	string qualified_name;
-	if (!die_qualified_type_name_empty(ctxt, die,
+	if (!die_qualified_type_name_empty(rdr, die,
 					   where_offset,
 					   qualified_name))
 	  repr = "typedef " + qualified_name;
@@ -10436,13 +9617,13 @@ die_pretty_print_type(read_context& ctxt,
     case DW_TAG_pointer_type:
     case DW_TAG_reference_type:
     case DW_TAG_rvalue_reference_type:
-      repr = ctxt.get_die_qualified_type_name(die, where_offset);
+      repr = rdr.get_die_qualified_type_name(die, where_offset);
       break;
 
     case DW_TAG_enumeration_type:
       {
 	string qualified_name =
-	  ctxt.get_die_qualified_type_name(die, where_offset);
+	  rdr.get_die_qualified_type_name(die, where_offset);
 	repr = "enum " + qualified_name;
       }
       break;
@@ -10451,7 +9632,7 @@ die_pretty_print_type(read_context& ctxt,
     case DW_TAG_class_type:
       {
 	string qualified_name =
-	  ctxt.get_die_qualified_type_name(die, where_offset);
+	  rdr.get_die_qualified_type_name(die, where_offset);
 	repr = "class " + qualified_name;
       }
       break;
@@ -10459,7 +9640,7 @@ die_pretty_print_type(read_context& ctxt,
     case DW_TAG_union_type:
       {
 	string qualified_name =
-	  ctxt.get_die_qualified_type_name(die, where_offset);
+	  rdr.get_die_qualified_type_name(die, where_offset);
 	repr = "union " + qualified_name;
       }
       break;
@@ -10470,12 +9651,12 @@ die_pretty_print_type(read_context& ctxt,
 	if (!die_die_attribute(die, DW_AT_type, element_type_die))
 	  break;
 	string element_type_name =
-	  ctxt.get_die_qualified_type_name(&element_type_die, where_offset);
+	  rdr.get_die_qualified_type_name(&element_type_die, where_offset);
 	if (element_type_name.empty())
 	  break;
 
 	array_type_def::subranges_type subranges;
-	build_subranges_from_array_type_die(ctxt, die, subranges, where_offset,
+	build_subranges_from_array_type_die(rdr, die, subranges, where_offset,
 					    /*associate_type_to_die=*/false);
 
 	repr = element_type_name;
@@ -10493,7 +9674,7 @@ die_pretty_print_type(read_context& ctxt,
 	// subrange type is its name.  We might need something more
 	// advance, should the needs of the users get more
 	// complicated.
-	repr += die_qualified_type_name(ctxt, die, where_offset);
+	repr += die_qualified_type_name(rdr, die, where_offset);
       }
       break;
 
@@ -10506,7 +9687,7 @@ die_pretty_print_type(read_context& ctxt,
 	bool is_const = false;
 	bool is_static = false;
 
-	die_return_and_parm_names_from_fn_type_die(ctxt, die, where_offset,
+	die_return_and_parm_names_from_fn_type_die(rdr, die, where_offset,
 						   /*pretty_print=*/true,
 						   return_type_name, class_name,
 						   parm_names, is_const,
@@ -10515,7 +9696,7 @@ die_pretty_print_type(read_context& ctxt,
 	  repr = "function type";
 	else
 	  repr = "method type";
-	repr += " " + ctxt.get_die_qualified_type_name(die, where_offset);
+	repr += " " + rdr.get_die_qualified_type_name(die, where_offset);
       }
       break;
 
@@ -10540,7 +9721,7 @@ die_pretty_print_type(read_context& ctxt,
 /// Note that this function is also used to pretty print functions.
 /// For functions, it prints the signature of the function.
 ///
-/// @param ctxt the context to use.
+/// @param rdr the context to use.
 ///
 /// @param the DIE of the declaration to pretty print.
 ///
@@ -10550,7 +9731,7 @@ die_pretty_print_type(read_context& ctxt,
 ///
 /// @return the resulting pretty representation.
 static string
-die_pretty_print_decl(read_context& ctxt,
+die_pretty_print_decl(reader& rdr,
 		      const Dwarf_Die* die,
 		      size_t where_offset)
 {
@@ -10563,7 +9744,7 @@ die_pretty_print_decl(read_context& ctxt,
   switch (tag)
     {
     case DW_TAG_namespace:
-      repr = "namespace " + die_qualified_name(ctxt, die, where_offset);
+      repr = "namespace " + die_qualified_name(rdr, die, where_offset);
       break;
 
     case DW_TAG_member:
@@ -10572,15 +9753,15 @@ die_pretty_print_decl(read_context& ctxt,
 	string type_repr = "void";
 	Dwarf_Die type_die;
 	if (die_die_attribute(die, DW_AT_type, type_die))
-	  type_repr = die_qualified_type_name(ctxt, &type_die, where_offset);
-	repr = die_qualified_name(ctxt, die, where_offset);
+	  type_repr = die_qualified_type_name(rdr, &type_die, where_offset);
+	repr = die_qualified_name(rdr, die, where_offset);
 	if (!repr.empty())
 	  repr = type_repr + " " + repr;
       }
       break;
 
     case DW_TAG_subprogram:
-      repr = die_function_signature(ctxt, die, where_offset);
+      repr = die_function_signature(rdr, die, where_offset);
       break;
 
     default:
@@ -10598,7 +9779,7 @@ die_pretty_print_decl(read_context& ctxt,
 /// DW_TAG_subprogram DIE is going to be represented as a function
 /// *type*.
 ///
-/// @param ctxt the reading context.
+/// @param rdr the DWARF reader.
 ///
 /// @param die the DIE to consider.
 ///
@@ -10606,12 +9787,12 @@ die_pretty_print_decl(read_context& ctxt,
 ///
 /// @return a copy of the pretty printed artifact.
 static string
-die_pretty_print(read_context& ctxt, const Dwarf_Die* die, size_t where_offset)
+die_pretty_print(reader& rdr, const Dwarf_Die* die, size_t where_offset)
 {
   if (die_is_type(die))
-    return die_pretty_print_type(ctxt, die, where_offset);
+    return die_pretty_print_type(rdr, die, where_offset);
   else if (die_is_decl(die))
-    return die_pretty_print_decl(ctxt, die, where_offset);
+    return die_pretty_print_decl(rdr, die, where_offset);
   return "";
 }
 
@@ -10675,7 +9856,7 @@ compare_as_decl_dies(const Dwarf_Die *l, const Dwarf_Die *r)
 
 /// Test if at least one of two ODR-relevant DIEs is decl-only.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param l the first type DIE to consider.
 ///
@@ -10684,11 +9865,11 @@ compare_as_decl_dies(const Dwarf_Die *l, const Dwarf_Die *r)
 /// @return true iff either @p l or @p r is decl-only and both are
 /// ODR-relevant.
 static bool
-at_least_one_decl_only_among_odr_relevant_dies(const read_context &ctxt,
+at_least_one_decl_only_among_odr_relevant_dies(const reader &rdr,
 					       const Dwarf_Die *l,
 					       const Dwarf_Die *r)
 {
-  if (!(ctxt.odr_is_relevant(l) && ctxt.odr_is_relevant(r)))
+  if (!(rdr.odr_is_relevant(l) && rdr.odr_is_relevant(r)))
     return false;
 
   if ((die_is_declaration_only(l) && die_has_no_child(l))
@@ -10711,7 +9892,7 @@ at_least_one_decl_only_among_odr_relevant_dies(const read_context &ctxt,
 /// a declaration of a type compares equal to the definition of the
 /// type.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param l the left operand of the comparison operator.
 ///
@@ -10719,7 +9900,7 @@ at_least_one_decl_only_among_odr_relevant_dies(const read_context &ctxt,
 ///
 /// @return true iff @p l equals @p r.
 static bool
-compare_as_type_dies(const read_context& ctxt,
+compare_as_type_dies(const reader& rdr,
 		     const Dwarf_Die *l,
 		     const Dwarf_Die *r)
 {
@@ -10738,7 +9919,7 @@ compare_as_type_dies(const read_context& ctxt,
     // DW_TAG_string_type DIEs are different, by default.
     return false;
 
-  if (at_least_one_decl_only_among_odr_relevant_dies(ctxt, l, r))
+  if (at_least_one_decl_only_among_odr_relevant_dies(rdr, l, r))
     // A declaration of a type compares equal to the definition of the
     // type.
     return true;
@@ -10753,7 +9934,7 @@ compare_as_type_dies(const read_context& ctxt,
 /// Compare two DIEs as decls (looking as their names etc) and as
 /// types (looking at their size etc).
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param l the first DIE to consider.
 ///
@@ -10762,12 +9943,12 @@ compare_as_type_dies(const read_context& ctxt,
 /// @return TRUE iff @p l equals @p r as far as naming and size is
 /// concerned.
 static bool
-compare_as_decl_and_type_dies(const read_context &ctxt,
+compare_as_decl_and_type_dies(const reader &rdr,
 			      const Dwarf_Die *l,
 			      const Dwarf_Die *r)
 {
   if (!compare_as_decl_dies(l, r)
-      || !compare_as_type_dies(ctxt, l, r))
+      || !compare_as_type_dies(rdr, l, r))
     return false;
 
   return true;
@@ -10782,7 +9963,7 @@ compare_as_decl_and_type_dies(const read_context &ctxt,
 /// in C++ for instance, that doesn't imply that the two functions are
 /// equal.
 ///
-/// @param ctxt the @ref read_context to consider.
+/// @param rdr the @ref reader to consider.
 ///
 /// @param l the first function DIE to consider.
 ///
@@ -10791,7 +9972,7 @@ compare_as_decl_and_type_dies(const read_context &ctxt,
 /// @return true iff the function represented by @p l have the same
 /// linkage name as the function represented by @p r.
 static bool
-fn_die_equal_by_linkage_name(const read_context &ctxt,
+fn_die_equal_by_linkage_name(const reader &rdr,
 			     const Dwarf_Die *l,
 			     const Dwarf_Die *r)
 {
@@ -10810,8 +9991,8 @@ fn_die_equal_by_linkage_name(const read_context &ctxt,
   string llinkage_name = die_linkage_name(l),
     rlinkage_name = die_linkage_name(r);
 
-  if (ctxt.die_is_in_c_or_cplusplus(l)
-      && ctxt.die_is_in_c_or_cplusplus(r))
+  if (rdr.die_is_in_c_or_cplusplus(l)
+      && rdr.die_is_in_c_or_cplusplus(r))
     {
       if (!llinkage_name.empty() && !rlinkage_name.empty())
 	return llinkage_name == rlinkage_name;
@@ -10832,7 +10013,7 @@ fn_die_equal_by_linkage_name(const read_context &ctxt,
 /// canonically and structurally.  The two types of comparison should
 /// be equal, of course.
 ///
-/// @param ctxt the read_context.
+/// @param rdr the DWARF reader.
 ///
 /// @param l_offset the offset of the first canonical DIE to compare.
 ///
@@ -10855,7 +10036,7 @@ fn_die_equal_by_linkage_name(const read_context &ctxt,
 /// set to the offset of the canonical DIE of the DIE designated by @p
 /// l_offset.
 static bool
-try_canonical_die_comparison(const read_context& ctxt,
+try_canonical_die_comparison(const reader& rdr,
 			     Dwarf_Off l_offset, Dwarf_Off r_offset,
 			     die_source l_die_source, die_source r_die_source,
 			     bool& l_has_canonical_die_offset,
@@ -10865,20 +10046,20 @@ try_canonical_die_comparison(const read_context& ctxt,
 			     bool& result)
 {
 #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
-  if (ctxt.debug_die_canonicalization_is_on_
-      && !ctxt.use_canonical_die_comparison_)
+  if (rdr.debug_die_canonicalization_is_on_
+      && !rdr.use_canonical_die_comparison_)
     return false;
 #endif
 
 
   l_has_canonical_die_offset =
     (l_canonical_die_offset =
-     ctxt.get_canonical_die_offset(l_offset, l_die_source,
+     rdr.get_canonical_die_offset(l_offset, l_die_source,
 				   /*die_as_type=*/true));
 
   r_has_canonical_die_offset =
     (r_canonical_die_offset =
-     ctxt.get_canonical_die_offset(r_offset, r_die_source,
+     rdr.get_canonical_die_offset(r_offset, r_die_source,
 				   /*die_as_type=*/true));
 
   if (l_has_canonical_die_offset && r_has_canonical_die_offset)
@@ -11085,7 +10266,7 @@ get_member_child_die(const Dwarf_Die *die, Dwarf_Die *child)
 /// This optimization is performed only if
 /// is_canon_type_to_be_propagated_tag returns true.
 ///
-/// @param ctxt the current context to consider.
+/// @param rdr the current context to consider.
 ///
 /// @param l the left-hand-side DIE of the comparison.  It's going to
 /// receive the canonical type of the other DIE.
@@ -11093,7 +10274,7 @@ get_member_child_die(const Dwarf_Die *die, Dwarf_Die *child)
 /// @param r the right-hand-side DIE of the comparison.  Its canonical
 /// type is propagated to @p l.
 static void
-maybe_propagate_canonical_type(const read_context& ctxt,
+maybe_propagate_canonical_type(const reader& rdr,
 			       const Dwarf_Die* l,
 			       const Dwarf_Die* r)
 {
@@ -11104,7 +10285,7 @@ maybe_propagate_canonical_type(const read_context& ctxt,
     return;
 
   if (is_canon_type_to_be_propagated_tag(l_tag))
-    propagate_canonical_type(ctxt, l, r);
+    propagate_canonical_type(rdr, l, r);
 }
 
 /// Propagate the canonical type of a the right-hand-side DIE to the
@@ -11114,7 +10295,7 @@ maybe_propagate_canonical_type(const read_context& ctxt,
 /// If the right-hand-side DIE is not canonicalized, the function
 /// performs its canonicalization.
 ///
-/// @param ctxt the current context to consider.
+/// @param rdr the current context to consider.
 ///
 /// @param l the left-hand-side DIE of the comparison.  It's going to
 /// receive the canonical type of the other DIE.
@@ -11122,7 +10303,7 @@ maybe_propagate_canonical_type(const read_context& ctxt,
 /// @param r the right-hand-side DIE of the comparison.  Its canonical
 /// type is propagated to @p l.
 static void
-propagate_canonical_type(const read_context& ctxt,
+propagate_canonical_type(const reader& rdr,
 			 const Dwarf_Die* l,
 			 const Dwarf_Die* r)
 {
@@ -11133,8 +10314,8 @@ propagate_canonical_type(const read_context& ctxt,
   //
   // In case 'r' has no canonical DIE, then compute it, and then
   // propagate that canonical DIE to 'r'.
-  const die_source l_source = ctxt.get_die_source(l);
-  const die_source r_source = ctxt.get_die_source(r);
+  const die_source l_source = rdr.get_die_source(l);
+  const die_source r_source = rdr.get_die_source(r);
 
   Dwarf_Off l_offset = dwarf_dieoffset(const_cast<Dwarf_Die*>(l));
   Dwarf_Off r_offset = dwarf_dieoffset(const_cast<Dwarf_Die*>(r));
@@ -11145,12 +10326,12 @@ propagate_canonical_type(const read_context& ctxt,
 
   l_has_canonical_die_offset =
     (l_canonical_die_offset =
-     ctxt.get_canonical_die_offset(l_offset, l_source,
+     rdr.get_canonical_die_offset(l_offset, l_source,
 				   /*die_as_type=*/true));
 
   r_has_canonical_die_offset =
     (r_canonical_die_offset =
-     ctxt.get_canonical_die_offset(r_offset, r_source,
+     rdr.get_canonical_die_offset(r_offset, r_source,
 				   /*die_as_type=*/true));
 
 
@@ -11160,14 +10341,14 @@ propagate_canonical_type(const read_context& ctxt,
       && l_source == r_source)
     {
       if (!r_has_canonical_die_offset)
-	ctxt.compute_canonical_die_offset(r, r_canonical_die_offset,
+	rdr.compute_canonical_die_offset(r, r_canonical_die_offset,
 					  /*die_as_type=*/true);
       ABG_ASSERT(r_canonical_die_offset);
-      ctxt.set_canonical_die_offset(l, r_canonical_die_offset,
+      rdr.set_canonical_die_offset(l, r_canonical_die_offset,
 				    /*die_as_type=*/true);
       offset_type l_off = {l_source, l_offset}, r_off = {r_source, r_offset};
-      ctxt.propagated_types_.insert(std::make_pair(l_off,r_off));
-      ctxt.canonical_propagated_count_++;
+      rdr.propagated_types_.insert(std::make_pair(l_off,r_off));
+      rdr.canonical_propagated_count_++;
     }
 }
 
@@ -11222,7 +10403,7 @@ return_comparison_result(const Dwarf_Die* l,
       if (do_propagate_canonical_type)
 	{
 	  // Propagate canonical type.
-	  maybe_propagate_canonical_type(comparison_stack.ctxt_, l, r);
+	  maybe_propagate_canonical_type(comparison_stack.rdr_, l, r);
 
 	  // TODO: do we need to confirm any tentative canonical
 	  // propagation?
@@ -11287,7 +10468,7 @@ return_comparison_result(const Dwarf_Die* l,
 	{
 	  // We are in the case described above of a redundant type
 	  // that has been fully compared.
-	  maybe_propagate_canonical_type(comparison_stack.ctxt_, l, r);
+	  maybe_propagate_canonical_type(comparison_stack.rdr_, l, r);
 	  comparison_stack.confirm_canonical_propagated_type(cur_dies);
 
 	  result = COMPARISON_RESULT_EQUAL;
@@ -11299,7 +10480,7 @@ return_comparison_result(const Dwarf_Die* l,
 	  // the introductory comment above, it must be dependant on a
 	  // redundant type.
 	  ABG_ASSERT(comparison_stack.depends_on_redundant_types(cur_dies));
-	  maybe_propagate_canonical_type(comparison_stack.ctxt_, l, r);
+	  maybe_propagate_canonical_type(comparison_stack.rdr_, l, r);
 	  // Then pass through.
 	}
     }
@@ -11341,7 +10522,7 @@ return_comparison_result(const Dwarf_Die* l,
     //and thus hasn't been pushed to the stack yet gain.
     comparison_stack.erase(cur_dies);
 
-  maybe_cache_type_comparison_result(comparison_stack.ctxt_,
+  maybe_cache_type_comparison_result(comparison_stack.rdr_,
 				     l_tag, cur_dies, result);
 
   return result;
@@ -11349,7 +10530,7 @@ return_comparison_result(const Dwarf_Die* l,
 
 /// Compare two DIEs emitted by a C compiler.
 ///
-/// @param ctxt the read context used to load the DWARF information.
+/// @param rdr the DWARF reader used to load the DWARF information.
 ///
 /// @param l the left-hand-side argument of this comparison operator.
 ///
@@ -11371,7 +10552,7 @@ return_comparison_result(const Dwarf_Die* l,
 ///
 /// @return COMPARISON_RESULT_EQUAL iff @p l equals @p r.
 static comparison_result
-compare_dies(const read_context& ctxt,
+compare_dies(const reader& rdr,
 	     const Dwarf_Die *l, const Dwarf_Die *r,
 	     offset_pairs_stack_type& aggregates_being_compared,
 	     bool update_canonical_dies_on_the_fly)
@@ -11379,8 +10560,8 @@ compare_dies(const read_context& ctxt,
   ABG_ASSERT(l);
   ABG_ASSERT(r);
 
-  const die_source l_die_source = ctxt.get_die_source(l);
-  const die_source r_die_source = ctxt.get_die_source(r);
+  const die_source l_die_source = rdr.get_die_source(l);
+  const die_source r_die_source = rdr.get_die_source(r);
 
   offset_type l_offset =
     {
@@ -11406,7 +10587,7 @@ compare_dies(const read_context& ctxt,
     return COMPARISON_RESULT_EQUAL;
 
   comparison_result result = COMPARISON_RESULT_EQUAL;
-  if (maybe_get_cached_type_comparison_result(ctxt, l_tag,
+  if (maybe_get_cached_type_comparison_result(rdr, l_tag,
 					      dies_being_compared,
 					      result))
     return result;
@@ -11419,7 +10600,7 @@ compare_dies(const read_context& ctxt,
   if (is_type_die_to_be_canonicalized(l) && is_type_die_to_be_canonicalized(r))
     {
       bool canonical_compare_result = false;
-      if (try_canonical_die_comparison(ctxt, l_offset, r_offset,
+      if (try_canonical_die_comparison(rdr, l_offset, r_offset,
 				       l_die_source, r_die_source,
 				       l_has_canonical_die_offset,
 				       r_has_canonical_die_offset,
@@ -11444,7 +10625,7 @@ compare_dies(const read_context& ctxt,
     case DW_TAG_base_type:
     case DW_TAG_string_type:
     case DW_TAG_unspecified_type:
-      if (!compare_as_decl_and_type_dies(ctxt, l, r))
+      if (!compare_as_decl_and_type_dies(rdr, l, r))
 	SET_RESULT_TO_FALSE(result, l, r);
       break;
 
@@ -11456,7 +10637,7 @@ compare_dies(const read_context& ctxt,
     case DW_TAG_volatile_type:
     case DW_TAG_restrict_type:
       {
-	if (!compare_as_type_dies(ctxt, l, r))
+	if (!compare_as_type_dies(rdr, l, r))
 	  {
 	    SET_RESULT_TO_FALSE(result, l, r);
 	    break;
@@ -11493,14 +10674,14 @@ compare_dies(const read_context& ctxt,
 	else if (lu_is_void != ru_is_void)
 	  SET_RESULT_TO_FALSE(result, l, r);
 	else
-	  result = compare_dies(ctxt, &lu_type_die, &ru_type_die,
+	  result = compare_dies(rdr, &lu_type_die, &ru_type_die,
 				aggregates_being_compared,
 				update_canonical_dies_on_the_fly);
       }
       break;
 
     case DW_TAG_enumeration_type:
-      if (!compare_as_decl_and_type_dies(ctxt, l, r))
+      if (!compare_as_decl_and_type_dies(rdr, l, r))
 	SET_RESULT_TO_FALSE(result, l, r);
       else
 	{
@@ -11508,7 +10689,7 @@ compare_dies(const read_context& ctxt,
 	  Dwarf_Die l_enumtor, r_enumtor;
 	  bool found_l_enumtor = true, found_r_enumtor = true;
 
-	  if (!at_least_one_decl_only_among_odr_relevant_dies(ctxt, l, r))
+	  if (!at_least_one_decl_only_among_odr_relevant_dies(rdr, l, r))
 	    for (found_l_enumtor = dwarf_child(const_cast<Dwarf_Die*>(l),
 					       &l_enumtor) == 0,
 		   found_r_enumtor = dwarf_child(const_cast<Dwarf_Die*>(r),
@@ -11551,9 +10732,9 @@ compare_dies(const read_context& ctxt,
       {
 	RETURN_IF_COMPARISON_CYCLE_DETECTED;
 
-	ctxt.compare_count_++;
+	rdr.compare_count_++;
 
-	if (!compare_as_decl_and_type_dies(ctxt, l, r))
+	if (!compare_as_decl_and_type_dies(rdr, l, r))
 	  SET_RESULT_TO_FALSE(result, l, r);
 	else
 	  {
@@ -11562,7 +10743,7 @@ compare_dies(const read_context& ctxt,
 	    Dwarf_Die l_member, r_member;
 	    bool found_l_member = true, found_r_member = true;
 
-	    if (!at_least_one_decl_only_among_odr_relevant_dies(ctxt, l, r))
+	    if (!at_least_one_decl_only_among_odr_relevant_dies(rdr, l, r))
 	      for (found_l_member = get_member_child_die(l, &l_member),
 		     found_r_member = get_member_child_die(r, &r_member);
 		   found_l_member && found_r_member;
@@ -11586,7 +10767,7 @@ compare_dies(const read_context& ctxt,
 			     || l_tag == DW_TAG_subprogram);
 
 		  comparison_result local_result =
-		    compare_dies(ctxt, &l_member, &r_member,
+		    compare_dies(rdr, &l_member, &r_member,
 				 aggregates_being_compared,
 				 update_canonical_dies_on_the_fly);
 
@@ -11622,7 +10803,7 @@ compare_dies(const read_context& ctxt,
 
 	aggregates_being_compared.add(dies_being_compared);
 
-	ctxt.compare_count_++;
+	rdr.compare_count_++;
 
 	Dwarf_Die l_child, r_child;
 	bool found_l_child, found_r_child;
@@ -11639,7 +10820,7 @@ compare_dies(const read_context& ctxt,
 	    if (l_child_tag == DW_TAG_subrange_type
 		|| r_child_tag == DW_TAG_subrange_type)
 	      {
-		result = compare_dies(ctxt, &l_child, &r_child,
+		result = compare_dies(rdr, &l_child, &r_child,
 				      aggregates_being_compared,
 				      update_canonical_dies_on_the_fly);
 		if (!result)
@@ -11657,7 +10838,7 @@ compare_dies(const read_context& ctxt,
 	bool found_rtype = die_die_attribute(r, DW_AT_type, rtype_die);
 	ABG_ASSERT(found_ltype && found_rtype);
 
-	result = compare_dies(ctxt, &ltype_die, &rtype_die,
+	result = compare_dies(rdr, &ltype_die, &rtype_die,
 			      aggregates_being_compared,
 			      update_canonical_dies_on_the_fly);
 	  if (!result)
@@ -11707,22 +10888,22 @@ compare_dies(const read_context& ctxt,
 
 	aggregates_being_compared.add(dies_being_compared);
 
-	ctxt.compare_count_++;
+	rdr.compare_count_++;
 
 	if (l_tag == DW_TAG_subprogram
-	    && !fn_die_equal_by_linkage_name(ctxt, l, r))
+	    && !fn_die_equal_by_linkage_name(rdr, l, r))
 	  {
 	    SET_RESULT_TO_FALSE(result, l, r);
 	    break;
 	  }
 	else if (l_tag == DW_TAG_subprogram
-		 && ctxt.die_is_in_c(l) && ctxt.die_is_in_c(r)
-		 /*&& fn_die_equal_by_linkage_name(ctxt, l, r)*/)
+		 && rdr.die_is_in_c(l) && rdr.die_is_in_c(r)
+		 /*&& fn_die_equal_by_linkage_name(rdr, l, r)*/)
 	  {
 	    result = COMPARISON_RESULT_EQUAL;
 	    break;
 	  }
-	else if (!ctxt.die_is_in_c(l) && !ctxt.die_is_in_c(r))
+	else if (!rdr.die_is_in_c(l) && !rdr.die_is_in_c(r))
 	  {
 	    // In C, we cannot have two different functions with the
 	    // same linkage name in a given binary.  But here we are
@@ -11735,7 +10916,7 @@ compare_dies(const read_context& ctxt,
 							    r_return_type);
 	    if (l_return_type_is_void != r_return_type_is_void
 		|| (!l_return_type_is_void
-		    && !compare_dies(ctxt,
+		    && !compare_dies(rdr,
 				     &l_return_type, &r_return_type,
 				     aggregates_being_compared,
 				     update_canonical_dies_on_the_fly)))
@@ -11762,7 +10943,7 @@ compare_dies(const read_context& ctxt,
 		      local_result = COMPARISON_RESULT_DIFFERENT;
 		    if (l_child_tag == DW_TAG_formal_parameter)
 		      local_result =
-			compare_dies(ctxt, &l_child, &r_child,
+			compare_dies(rdr, &l_child, &r_child,
 				     aggregates_being_compared,
 				     update_canonical_dies_on_the_fly);
 		    if (local_result == COMPARISON_RESULT_DIFFERENT)
@@ -11804,7 +10985,7 @@ compare_dies(const read_context& ctxt,
 	else if (!l_type_is_void)
 	  {
 	    comparison_result local_result =
-	      compare_dies(ctxt, &l_type, &r_type,
+	      compare_dies(rdr, &l_type, &r_type,
 			   aggregates_being_compared,
 			   update_canonical_dies_on_the_fly);
 	    SET_RESULT_TO(result, local_result, l, r);
@@ -11820,8 +11001,8 @@ compare_dies(const read_context& ctxt,
 	  if (l_tag == DW_TAG_member)
 	    {
 	      int64_t l_offset_in_bits = 0, r_offset_in_bits = 0;
-	      die_member_offset(ctxt, l, l_offset_in_bits);
-	      die_member_offset(ctxt, r, r_offset_in_bits);
+	      die_member_offset(rdr, l, l_offset_in_bits);
+	      die_member_offset(rdr, r, r_offset_in_bits);
 	      if (l_offset_in_bits != r_offset_in_bits)
 		SET_RESULT_TO_FALSE(result, l, r);
 	    }
@@ -11832,7 +11013,7 @@ compare_dies(const read_context& ctxt,
 	      ABG_ASSERT(die_die_attribute(l, DW_AT_type, l_type));
 	      ABG_ASSERT(die_die_attribute(r, DW_AT_type, r_type));
 	      comparison_result local_result =
-		compare_dies(ctxt, &l_type, &r_type,
+		compare_dies(rdr, &l_type, &r_type,
 			     aggregates_being_compared,
 			     update_canonical_dies_on_the_fly);
 	      SET_RESULT_TO(result, local_result, l, r);
@@ -11847,7 +11028,7 @@ compare_dies(const read_context& ctxt,
 	Dwarf_Die l_type, r_type;
 	ABG_ASSERT(die_die_attribute(l, DW_AT_type, l_type));
 	ABG_ASSERT(die_die_attribute(r, DW_AT_type, r_type));
-	result = compare_dies(ctxt, &l_type, &r_type,
+	result = compare_dies(rdr, &l_type, &r_type,
 			       aggregates_being_compared,
 			       update_canonical_dies_on_the_fly);
 	if (!result)
@@ -11865,8 +11046,8 @@ compare_dies(const read_context& ctxt,
 	  ABG_RETURN(COMPARISON_RESULT_DIFFERENT);
 
 	int64_t l_offset_in_bits = 0, r_offset_in_bits = 0;
-	die_member_offset(ctxt, l, l_offset_in_bits);
-	die_member_offset(ctxt, r, r_offset_in_bits);
+	die_member_offset(rdr, l, l_offset_in_bits);
+	die_member_offset(rdr, r, r_offset_in_bits);
 	if (l_offset_in_bits != r_offset_in_bits)
 	  ABG_RETURN(COMPARISON_RESULT_DIFFERENT);
       }
@@ -11882,7 +11063,7 @@ compare_dies(const read_context& ctxt,
 	Dwarf_Die l_type, r_type;
 	ABG_ASSERT(die_die_attribute(l, DW_AT_type, l_type));
 	ABG_ASSERT(die_die_attribute(r, DW_AT_type, r_type));
-	result = compare_dies(ctxt, &l_type, &r_type,
+	result = compare_dies(rdr, &l_type, &r_type,
 			      aggregates_being_compared,
 			      update_canonical_dies_on_the_fly);
 	if (!result)
@@ -11890,7 +11071,7 @@ compare_dies(const read_context& ctxt,
 
 	ABG_ASSERT(die_die_attribute(l, DW_AT_containing_type, l_type));
 	ABG_ASSERT(die_die_attribute(r, DW_AT_containing_type, r_type));
-	result = compare_dies(ctxt, &l_type, &r_type,
+	result = compare_dies(rdr, &l_type, &r_type,
 			      aggregates_being_compared,
 			      update_canonical_dies_on_the_fly);
 	if (!result)
@@ -11949,7 +11130,7 @@ compare_dies(const read_context& ctxt,
     case DW_TAG_GNU_call_site_parameter:
     case DW_TAG_hi_user:
 #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
-      if (ctxt.debug_die_canonicalization_is_on_)
+      if (rdr.debug_die_canonicalization_is_on_)
 	ABG_ASSERT_NOT_REACHED;
 #endif
       ABG_ASSERT_NOT_REACHED;
@@ -11961,7 +11142,7 @@ compare_dies(const read_context& ctxt,
 
 /// Compare two DIEs emitted by a C compiler.
 ///
-/// @param ctxt the read context used to load the DWARF information.
+/// @param rdr the DWARF reader used to load the DWARF information.
 ///
 /// @param l the left-hand-side argument of this comparison operator.
 ///
@@ -11976,25 +11157,25 @@ compare_dies(const read_context& ctxt,
 ///
 /// @return COMPARISON_RESULT_EQUAL iff @p l equals @p r.
 static comparison_result
-compare_dies(const read_context& ctxt,
+compare_dies(const reader& rdr,
 	     const Dwarf_Die *l,
 	     const Dwarf_Die *r,
 	     bool update_canonical_dies_on_the_fly)
 {
-  offset_pairs_stack_type aggregates_being_compared(ctxt);
-  return compare_dies(ctxt, l, r, aggregates_being_compared,
+  offset_pairs_stack_type aggregates_being_compared(rdr);
+  return compare_dies(rdr, l, r, aggregates_being_compared,
 		      update_canonical_dies_on_the_fly);
 }
 
 /// Compare two DIEs for the purpose of canonicalization.
 ///
-/// This is a sub-routine of read_context::get_canonical_die.
+/// This is a sub-routine of reader::get_canonical_die.
 ///
 /// When DIE canonicalization debugging is on, this function performs
 /// both structural and canonical comparison.  It expects that both
 /// comparison yield the same result.
 ///
-/// @param ctxt the read context.
+/// @param rdr the DWARF reader.
 ///
 /// @param l the left-hand-side comparison operand DIE.
 ///
@@ -12005,20 +11186,20 @@ compare_dies(const read_context& ctxt,
 ///
 /// @return true iff @p l equals @p r.
 static bool
-compare_dies_during_canonicalization(read_context& ctxt,
+compare_dies_during_canonicalization(reader& rdr,
 				     const Dwarf_Die *l,
 				     const Dwarf_Die *r,
 				     bool update_canonical_dies_on_the_fly)
 {
 #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
-  if (ctxt.debug_die_canonicalization_is_on_)
+  if (rdr.debug_die_canonicalization_is_on_)
     {
       bool canonical_equality = false, structural_equality = false;
-      ctxt.use_canonical_die_comparison_ = false;
-      structural_equality = compare_dies(ctxt, l, r,
+      rdr.use_canonical_die_comparison_ = false;
+      structural_equality = compare_dies(rdr, l, r,
 					 /*update_canonical_dies_on_the_fly=*/false);
-      ctxt.use_canonical_die_comparison_ = true;
-      canonical_equality = compare_dies(ctxt, l, r,
+      rdr.use_canonical_die_comparison_ = true;
+      canonical_equality = compare_dies(rdr, l, r,
 					update_canonical_dies_on_the_fly);
       if (canonical_equality != structural_equality)
 	{
@@ -12028,7 +11209,7 @@ compare_dies_during_canonicalization(read_context& ctxt,
 		    << ", r: " << dwarf_dieoffset(const_cast<Dwarf_Die*>(r))
 		    << std::dec
 		    << ", repr: '"
-		    << ctxt.get_die_pretty_type_representation(l, 0)
+		    << rdr.get_die_pretty_type_representation(l, 0)
 		    << "'"
 		    << std::endl;
 	  ABG_ASSERT_NOT_REACHED;
@@ -12036,7 +11217,7 @@ compare_dies_during_canonicalization(read_context& ctxt,
       return structural_equality;
     }
 #endif
-  return compare_dies(ctxt, l, r,
+  return compare_dies(rdr, l, r,
 		      update_canonical_dies_on_the_fly);
 }
 
@@ -12047,7 +11228,7 @@ compare_dies_during_canonicalization(read_context& ctxt,
 /// Get the point where a DW_AT_import DIE is used to import a given
 /// (unit) DIE, between two DIEs.
 ///
-/// @param ctxt the dwarf reading context to consider.
+/// @param rdr the dwarf reader to consider.
 ///
 /// @param partial_unit_offset the imported unit for which we want to
 /// know the insertion point.  This is usually a partial unit (with
@@ -12079,7 +11260,7 @@ compare_dies_during_canonicalization(read_context& ctxt,
 /// @return true iff an imported unit is found between @p
 /// first_die_offset and @p last_die_offset.
 static bool
-find_import_unit_point_between_dies(const read_context& ctxt,
+find_import_unit_point_between_dies(const reader& rdr,
 				    size_t		partial_unit_offset,
 				    Dwarf_Off		first_die_offset,
 				    Dwarf_Off		first_die_cu_offset,
@@ -12088,7 +11269,7 @@ find_import_unit_point_between_dies(const read_context& ctxt,
 				    size_t&		imported_point_offset)
 {
   const tu_die_imported_unit_points_map_type& tu_die_imported_unit_points_map =
-    ctxt.tu_die_imported_unit_points_map(source);
+    rdr.tu_die_imported_unit_points_map(source);
 
   tu_die_imported_unit_points_map_type::const_iterator iter =
     tu_die_imported_unit_points_map.find(first_die_cu_offset);
@@ -12122,7 +11303,7 @@ find_import_unit_point_between_dies(const read_context& ctxt,
 
       for (imported_unit_points_type::const_iterator i = e; i >= b; --i)
 	{
-	  if (find_import_unit_point_between_dies(ctxt,
+	  if (find_import_unit_point_between_dies(rdr,
 						  partial_unit_offset,
 						  i->imported_unit_child_off,
 						  i->imported_unit_cu_off,
@@ -12143,7 +11324,7 @@ find_import_unit_point_between_dies(const read_context& ctxt,
 
       for (imported_unit_points_type::const_iterator i = b; i != e; ++i)
 	{
-	  if (find_import_unit_point_between_dies(ctxt,
+	  if (find_import_unit_point_between_dies(rdr,
 						  partial_unit_offset,
 						  i->imported_unit_child_off,
 						  i->imported_unit_cu_off,
@@ -12164,7 +11345,7 @@ find_import_unit_point_between_dies(const read_context& ctxt,
 /// Said otherwise, this function returns the last import point of a
 /// unit, before a limit.
 ///
-/// @param ctxt the dwarf reading context to consider.
+/// @param rdr the dwarf reader to consider.
 ///
 /// @param partial_unit_offset the imported unit for which we want to
 /// know the insertion point of.  This is usually a partial unit (with
@@ -12182,7 +11363,7 @@ find_import_unit_point_between_dies(const read_context& ctxt,
 /// Note that if an imported unit is found after @p die_offset then @p
 /// imported_point_offset is set and the function return false.
 static bool
-find_import_unit_point_before_die(const read_context&	ctxt,
+find_import_unit_point_before_die(const reader&	rdr,
 				  size_t		partial_unit_offset,
 				  size_t		where_offset,
 				  size_t&		imported_point_offset)
@@ -12190,7 +11371,7 @@ find_import_unit_point_before_die(const read_context&	ctxt,
   size_t import_point_offset = 0;
   Dwarf_Die first_die_of_tu;
 
-  if (dwarf_child(const_cast<Dwarf_Die*>(ctxt.cur_tu_die()),
+  if (dwarf_child(const_cast<Dwarf_Die*>(rdr.cur_tu_die()),
 		  &first_die_of_tu) != 0)
     return false;
 
@@ -12200,7 +11381,7 @@ find_import_unit_point_before_die(const read_context&	ctxt,
   cu_die = dwarf_diecu(const_cast<Dwarf_Die*>(&first_die_of_tu),
 		       &cu_die_memory, 0, 0);
 
-  if (find_import_unit_point_between_dies(ctxt, partial_unit_offset,
+  if (find_import_unit_point_between_dies(rdr, partial_unit_offset,
 					  dwarf_dieoffset(&first_die_of_tu),
 					  dwarf_dieoffset(cu_die),
 					  /*source=*/PRIMARY_DEBUG_INFO_DIE_SOURCE,
@@ -12226,7 +11407,7 @@ find_import_unit_point_before_die(const read_context&	ctxt,
 /// called before this one can work.  This function either succeeds or
 /// aborts the current process.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param die the DIE for which we want the parent.
 ///
@@ -12241,16 +11422,16 @@ find_import_unit_point_before_die(const read_context&	ctxt,
 /// @return true if the function could get a parent DIE, false
 /// otherwise.
 static bool
-get_parent_die(const read_context&	ctxt,
+get_parent_die(const reader&	rdr,
 	       const Dwarf_Die*	die,
 	       Dwarf_Die&		parent_die,
 	       size_t			where_offset)
 {
-  ABG_ASSERT(ctxt.dwarf());
+  ABG_ASSERT(rdr.dwarf_debug_info());
 
-  const die_source source = ctxt.get_die_source(die);
+  const die_source source = rdr.get_die_source(die);
 
-  const offset_offset_map_type& m = ctxt.die_parent_map(source);
+  const offset_offset_map_type& m = rdr.die_parent_map(source);
   offset_offset_map_type::const_iterator i =
     m.find(dwarf_dieoffset(const_cast<Dwarf_Die*>(die)));
 
@@ -12260,13 +11441,16 @@ get_parent_die(const read_context&	ctxt,
   switch (source)
     {
     case PRIMARY_DEBUG_INFO_DIE_SOURCE:
-      ABG_ASSERT(dwarf_offdie(ctxt.dwarf(), i->second, &parent_die));
+      ABG_ASSERT(dwarf_offdie(const_cast<Dwarf*>(rdr.dwarf_debug_info()),
+			      i->second, &parent_die));
       break;
     case ALT_DEBUG_INFO_DIE_SOURCE:
-      ABG_ASSERT(dwarf_offdie(ctxt.alt_dwarf(), i->second, &parent_die));
+      ABG_ASSERT(dwarf_offdie(const_cast<Dwarf*>(rdr.alternate_dwarf_debug_info()),
+			      i->second, &parent_die));
       break;
     case TYPE_UNIT_DIE_SOURCE:
-      ABG_ASSERT(dwarf_offdie_types(ctxt.dwarf(), i->second, &parent_die));
+      ABG_ASSERT(dwarf_offdie_types(const_cast<Dwarf*>(rdr.dwarf_debug_info()),
+				    i->second, &parent_die));
       break;
     case NO_DEBUG_INFO_DIE_SOURCE:
     case NUMBER_OF_DIE_SOURCES:
@@ -12277,12 +11461,12 @@ get_parent_die(const read_context&	ctxt,
     {
       if (where_offset == 0)
 	{
-	  parent_die = *ctxt.cur_tu_die();
+	  parent_die = *rdr.cur_tu_die();
 	  return true;
 	}
       size_t import_point_offset = 0;
       bool found =
-	find_import_unit_point_before_die(ctxt,
+	find_import_unit_point_before_die(rdr,
 					  dwarf_dieoffset(&parent_die),
 					  where_offset,
 					  import_point_offset);
@@ -12291,15 +11475,15 @@ get_parent_die(const read_context&	ctxt,
 	// debug info file) hasn't been imported into this TU.  So,
 	// Let's assume its logical parent is the DIE of the current
 	// TU.
-	parent_die = *ctxt.cur_tu_die();
+	parent_die = *rdr.cur_tu_die();
       else
 	{
 	  ABG_ASSERT(import_point_offset);
 	  Dwarf_Die import_point_die;
-	  ABG_ASSERT(dwarf_offdie(ctxt.dwarf(),
-			      import_point_offset,
-			      &import_point_die));
-	  return get_parent_die(ctxt, &import_point_die,
+	  ABG_ASSERT(dwarf_offdie(const_cast<Dwarf*>(rdr.dwarf_debug_info()),
+				  import_point_offset,
+				  &import_point_die));
+	  return get_parent_die(rdr, &import_point_die,
 				parent_die, where_offset);
 	}
     }
@@ -12318,7 +11502,7 @@ get_parent_die(const read_context&	ctxt,
 /// Also note that if the current translation unit is from C, then
 /// this returns the global scope.
 ///
-/// @param ctxt the reading context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @param die the DIE to consider.
 ///
@@ -12327,12 +11511,12 @@ get_parent_die(const read_context&	ctxt,
 /// @param scope_die out parameter.  This is set to the resulting
 /// scope DIE iff the function returns true.
 static bool
-get_scope_die(const read_context&	ctxt,
+get_scope_die(const reader&	rdr,
 	      const Dwarf_Die*		die,
 	      size_t			where_offset,
 	      Dwarf_Die&		scope_die)
 {
-  if (is_c_language(ctxt.cur_transl_unit()->get_language()))
+  if (is_c_language(rdr.cur_transl_unit()->get_language()))
     {
       ABG_ASSERT(dwarf_tag(const_cast<Dwarf_Die*>(die)) != DW_TAG_member);
       return dwarf_diecu(const_cast<Dwarf_Die*>(die), &scope_die, 0, 0);
@@ -12343,15 +11527,15 @@ get_scope_die(const read_context&	ctxt,
 			logical_parent_die, false)
       || die_die_attribute(die, DW_AT_abstract_origin,
 			   logical_parent_die, false))
-    return get_scope_die(ctxt, &logical_parent_die, where_offset, scope_die);
+    return get_scope_die(rdr, &logical_parent_die, where_offset, scope_die);
 
-  if (!get_parent_die(ctxt, die, scope_die, where_offset))
+  if (!get_parent_die(rdr, die, scope_die, where_offset))
     return false;
 
   if (dwarf_tag(&scope_die) == DW_TAG_subprogram
       || dwarf_tag(&scope_die) == DW_TAG_subroutine_type
       || dwarf_tag(&scope_die) == DW_TAG_array_type)
-    return get_scope_die(ctxt, &scope_die, where_offset, scope_die);
+    return get_scope_die(rdr, &scope_die, where_offset, scope_die);
 
   return true;
 }
@@ -12366,7 +11550,7 @@ get_scope_die(const read_context&	ctxt,
 /// Also note that if the current translation unit is from C, then
 /// this returns the global scope.
 ///
-/// @param ctxt the dwarf reading context to use.
+/// @param rdr the dwarf reader to use.
 ///
 /// @param die the DIE to get the scope for.
 ///
@@ -12378,36 +11562,36 @@ get_scope_die(const read_context&	ctxt,
 /// e.g, DW_TAG_partial_unit that can be included in several places in
 /// the DIE tree.
 static scope_decl_sptr
-get_scope_for_die(read_context& ctxt,
+get_scope_for_die(reader& rdr,
 		  Dwarf_Die*	die,
 		  bool		called_for_public_decl,
 		  size_t	where_offset)
 {
-  const die_source source_of_die = ctxt.get_die_source(die);
+  const die_source source_of_die = rdr.get_die_source(die);
 
   translation_unit::language die_lang = translation_unit::LANG_UNKNOWN;
-  ctxt.get_die_language(die, die_lang);
+  rdr.get_die_language(die, die_lang);
   if (is_c_language(die_lang)
-      || ctxt.die_parent_map(source_of_die).empty())
+      || rdr.die_parent_map(source_of_die).empty())
     {
       // In units for the C languages all decls belong to the global
       // namespace.  This is generally the case if Libabigail
       // determined that no DIE -> parent map was needed.
       ABG_ASSERT(dwarf_tag(die) != DW_TAG_member);
-      return ctxt.global_scope();
+      return rdr.global_scope();
     }
 
   Dwarf_Die cloned_die;
   if (die_die_attribute(die, DW_AT_specification, cloned_die, false)
       || die_die_attribute(die, DW_AT_abstract_origin, cloned_die, false))
-    return get_scope_for_die(ctxt, &cloned_die,
+    return get_scope_for_die(rdr, &cloned_die,
 			     called_for_public_decl,
 			     where_offset);
 
   Dwarf_Die parent_die;
 
-  if (!get_parent_die(ctxt, die, parent_die, where_offset))
-    return ctxt.nil_scope();
+  if (!get_parent_die(rdr, die, parent_die, where_offset))
+    return rdr.nil_scope();
 
   if (dwarf_tag(&parent_die) == DW_TAG_compile_unit
       || dwarf_tag(&parent_die) == DW_TAG_partial_unit
@@ -12418,7 +11602,7 @@ get_scope_for_die(read_context& ctxt,
 	{
 	  ABG_ASSERT(source_of_die == ALT_DEBUG_INFO_DIE_SOURCE
 		 || source_of_die == TYPE_UNIT_DIE_SOURCE);
-	  return ctxt.cur_transl_unit()->get_global_scope();
+	  return rdr.cur_transl_unit()->get_global_scope();
 	}
 
       // For top level DIEs like DW_TAG_compile_unit, we just want to
@@ -12428,10 +11612,10 @@ get_scope_for_die(read_context& ctxt,
       // build the translation unit of parent_die.  Otherwise, just
       // return the global scope of the current translation unit.
       die_tu_map_type::const_iterator i =
-	ctxt.die_tu_map().find(dwarf_dieoffset(&parent_die));
-      if (i != ctxt.die_tu_map().end())
+	rdr.die_tu_map().find(dwarf_dieoffset(&parent_die));
+      if (i != rdr.die_tu_map().end())
 	return i->second->get_global_scope();
-      return ctxt.cur_transl_unit()->get_global_scope();
+      return rdr.cur_transl_unit()->get_global_scope();
     }
 
   scope_decl_sptr s;
@@ -12448,7 +11632,7 @@ get_scope_for_die(read_context& ctxt,
     // an error of the DWARF emitter.  We should never see this DIE in
     // this context.
     {
-      scope_decl_sptr s = get_scope_for_die(ctxt, &parent_die,
+      scope_decl_sptr s = get_scope_for_die(rdr, &parent_die,
 					    called_for_public_decl,
 					    where_offset);
       if (is_anonymous_type_die(die))
@@ -12458,23 +11642,23 @@ get_scope_for_die(read_context& ctxt,
 	// or union where it has nothing to do.
 	while (is_class_or_union_type(s))
 	  {
-	    if (!get_parent_die(ctxt, &parent_die, parent_die, where_offset))
-	      return ctxt.nil_scope();
-	    s = get_scope_for_die(ctxt, &parent_die,
+	    if (!get_parent_die(rdr, &parent_die, parent_die, where_offset))
+	      return rdr.nil_scope();
+	    s = get_scope_for_die(rdr, &parent_die,
 				  called_for_public_decl,
 				  where_offset);
 	  }
       return s;
     }
   else
-    d = build_ir_node_from_die(ctxt, &parent_die,
+    d = build_ir_node_from_die(rdr, &parent_die,
 			       called_for_public_decl,
 			       where_offset);
   s =  dynamic_pointer_cast<scope_decl>(d);
   if (!s)
     // this is an entity defined in someting that is not a scope.
     // Let's drop it.
-    return ctxt.nil_scope();
+    return rdr.nil_scope();
 
   class_decl_sptr cl = dynamic_pointer_cast<class_decl>(d);
   if (cl && cl->get_is_declaration_only())
@@ -12689,7 +11873,7 @@ find_lower_bound_in_imported_unit_points(const imported_unit_points_type& p,
 /// recursively reads the children dies of the current DIE and
 /// populates the resulting translation unit.
 ///
-/// @param ctxt the read_context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @param die the DW_TAG_compile_unit DIE to consider.
 ///
@@ -12698,7 +11882,7 @@ find_lower_bound_in_imported_unit_points(const imported_unit_points_type& p,
 ///
 /// @return a pointer to the resulting translation_unit.
 static translation_unit_sptr
-build_translation_unit_and_add_to_ir(read_context&	ctxt,
+build_translation_unit_and_add_to_ir(reader&	rdr,
 				     Dwarf_Die*	die,
 				     char		address_size)
 {
@@ -12710,9 +11894,9 @@ build_translation_unit_and_add_to_ir(read_context&	ctxt,
 
   // Clear the part of the context that is dependent on the translation
   // unit we are reading.
-  ctxt.clear_per_translation_unit_data();
+  rdr.clear_per_translation_unit_data();
 
-  ctxt.cur_tu_die(die);
+  rdr.cur_tu_die(die);
 
   string path = die_string_attribute(die, DW_AT_name);
   if (path == "<artificial>")
@@ -12737,23 +11921,23 @@ build_translation_unit_and_add_to_ir(read_context&	ctxt,
   {
     const string& abs_path =
       compilation_dir.empty() ? path : compilation_dir + "/" + path;
-    result = ctxt.current_corpus()->find_translation_unit(abs_path);
+    result = rdr.corpus()->find_translation_unit(abs_path);
   }
 
   if (!result)
     {
-      result.reset(new translation_unit(ctxt.env(),
+      result.reset(new translation_unit(rdr.env(),
 					path,
 					address_size));
       result->set_compilation_dir_path(compilation_dir);
-      ctxt.current_corpus()->add(result);
+      rdr.corpus()->add(result);
       uint64_t l = 0;
       die_unsigned_constant_attribute(die, DW_AT_language, l);
       result->set_language(dwarf_language_to_tu_language(l));
     }
 
-  ctxt.cur_transl_unit(result);
-  ctxt.die_tu_map()[dwarf_dieoffset(die)] = result;
+  rdr.cur_transl_unit(result);
+  rdr.die_tu_map()[dwarf_dieoffset(die)] = result;
 
   Dwarf_Die child;
   if (dwarf_child(die, &child) != 0)
@@ -12764,17 +11948,17 @@ build_translation_unit_and_add_to_ir(read_context&	ctxt,
   do
     // Analyze all the DIEs we encounter unless we are asked to only
     // analyze exported interfaces and the types reachables from them.
-    if (!ctxt.env()->analyze_exported_interfaces_only()
-	|| ctxt.is_decl_die_with_exported_symbol(&child))
-      build_ir_node_from_die(ctxt, &child,
+    if (!rdr.env().analyze_exported_interfaces_only()
+	|| rdr.is_decl_die_with_exported_symbol(&child))
+      build_ir_node_from_die(rdr, &child,
 			     die_is_public_decl(&child),
 			     dwarf_dieoffset(&child));
   while (dwarf_siblingof(&child, &child) == 0);
 
-  if (!ctxt.var_decls_to_re_add_to_tree().empty())
+  if (!rdr.var_decls_to_re_add_to_tree().empty())
     for (list<var_decl_sptr>::const_iterator v =
-	   ctxt.var_decls_to_re_add_to_tree().begin();
-	 v != ctxt.var_decls_to_re_add_to_tree().end();
+	   rdr.var_decls_to_re_add_to_tree().begin();
+	 v != rdr.var_decls_to_re_add_to_tree().end();
 	 ++v)
       {
 	if (is_member_decl(*v))
@@ -12795,7 +11979,7 @@ build_translation_unit_and_add_to_ir(read_context&	ctxt,
 	      {
 		ty_name = components_to_type_name(fqn_comps);
 		class_type =
-		  lookup_class_type(ty_name, *ctxt.cur_transl_unit());
+		  lookup_class_type(ty_name, *rdr.cur_transl_unit());
 	      }
 	    if (class_type)
 	      {
@@ -12825,7 +12009,7 @@ build_translation_unit_and_add_to_ir(read_context&	ctxt,
 	      }
 	  }
       }
-  ctxt.var_decls_to_re_add_to_tree().clear();
+  rdr.var_decls_to_re_add_to_tree().clear();
 
   result->set_is_constructed(true);
 
@@ -12839,7 +12023,7 @@ build_translation_unit_and_add_to_ir(read_context&	ctxt,
 /// being currently created, reads the children of the DIE and
 /// connects them to the IR as well.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @param die the DIE to read from.  Must be either DW_TAG_namespace
 /// or DW_TAG_module.
@@ -12852,7 +12036,7 @@ build_translation_unit_and_add_to_ir(read_context&	ctxt,
 /// @return the resulting @ref abigail::namespace_decl or NULL if it
 /// couldn't be created.
 static namespace_decl_sptr
-build_namespace_decl_and_add_to_ir(read_context&	ctxt,
+build_namespace_decl_and_add_to_ir(reader&	rdr,
 				   Dwarf_Die*		die,
 				   size_t		where_offset)
 {
@@ -12865,25 +12049,25 @@ build_namespace_decl_and_add_to_ir(read_context&	ctxt,
   if (tag != DW_TAG_namespace && tag != DW_TAG_module)
     return result;
 
-  scope_decl_sptr scope = get_scope_for_die(ctxt, die,
+  scope_decl_sptr scope = get_scope_for_die(rdr, die,
 					    /*called_for_public_decl=*/false,
 					    where_offset);
 
   string name, linkage_name;
   location loc;
-  die_loc_and_name(ctxt, die, loc, name, linkage_name);
+  die_loc_and_name(rdr, die, loc, name, linkage_name);
 
-  result.reset(new namespace_decl(ctxt.env(), name, loc));
+  result.reset(new namespace_decl(rdr.env(), name, loc));
   add_decl_to_scope(result, scope.get());
-  ctxt.associate_die_to_decl(die, result, where_offset);
+  rdr.associate_die_to_decl(die, result, where_offset);
 
   Dwarf_Die child;
   if (dwarf_child(die, &child) != 0)
     return result;
 
-  ctxt.scope_stack().push(result.get());
+  rdr.scope_stack().push(result.get());
   do
-    build_ir_node_from_die(ctxt, &child,
+    build_ir_node_from_die(rdr, &child,
 			   // If this namespace DIE is private
 			   // (anonymous) then all its content is
 			   // considered private.  Otherwise, its
@@ -12892,14 +12076,14 @@ build_namespace_decl_and_add_to_ir(read_context&	ctxt,
 			   die_is_public_decl(die) && die_is_public_decl(&child),
 			   where_offset);
   while (dwarf_siblingof(&child, &child) == 0);
-  ctxt.scope_stack().pop();
+  rdr.scope_stack().pop();
 
   return result;
 }
 
 /// Build a @ref type_decl out of a DW_TAG_base_type DIE.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @param die the DW_TAG_base_type to consider.
 ///
@@ -12907,7 +12091,7 @@ build_namespace_decl_and_add_to_ir(read_context&	ctxt,
 ///
 /// @return the resulting decl_base_sptr.
 static type_decl_sptr
-build_type_decl(read_context& ctxt, Dwarf_Die* die, size_t where_offset)
+build_type_decl(reader& rdr, Dwarf_Die* die, size_t where_offset)
 {
   type_decl_sptr result;
 
@@ -12926,21 +12110,21 @@ build_type_decl(read_context& ctxt, Dwarf_Die* die, size_t where_offset)
 
   string type_name, linkage_name;
   location loc;
-  die_loc_and_name(ctxt, die, loc, type_name, linkage_name);
+  die_loc_and_name(rdr, die, loc, type_name, linkage_name);
 
   if (byte_size == 0)
     {
       // The size of the type is zero, that must mean that we are
       // looking at the definition of the void type.
       if (type_name == "void")
-	result = is_type_decl(build_ir_node_for_void_type(ctxt));
+	result = is_type_decl(build_ir_node_for_void_type(rdr));
       else
 	// A type of size zero that is not void? Hmmh, I am not sure
 	// what that means.  Return nil for now.
 	return result;
     }
 
-  if (corpus_sptr corp = ctxt.should_reuse_type_from_corpus_group())
+  if (corpus_sptr corp = rdr.should_reuse_type_from_corpus_group())
     {
       string normalized_type_name = type_name;
       integral_type int_type;
@@ -12950,19 +12134,19 @@ build_type_decl(read_context& ctxt, Dwarf_Die* die, size_t where_offset)
     }
 
   if (!result)
-    if (corpus_sptr corp = ctxt.current_corpus())
+    if (corpus_sptr corp = rdr.corpus())
       result = lookup_basic_type(type_name, *corp);
   if (!result)
-    result.reset(new type_decl(ctxt.env(), type_name, bit_size,
+    result.reset(new type_decl(rdr.env(), type_name, bit_size,
 			       /*alignment=*/0, loc, linkage_name));
-  ctxt.associate_die_to_type(die, result, where_offset);
+  rdr.associate_die_to_type(die, result, where_offset);
   return result;
 }
 
 /// Construct the type that is to be used as the underlying type of an
 /// enum.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @param enum_name the name of the enum that this type is going to
 /// be the underlying type of.
@@ -12973,7 +12157,7 @@ build_type_decl(read_context& ctxt, Dwarf_Die* die, size_t where_offset)
 /// not. By default, this should be set to true as before c++11 (and
 /// in C), it's almost the case.
 static type_decl_sptr
-build_enum_underlying_type(read_context& ctxt,
+build_enum_underlying_type(reader& rdr,
 			   string enum_name,
 			   uint64_t enum_size,
 			   bool is_anonymous = true)
@@ -12982,11 +12166,11 @@ build_enum_underlying_type(read_context& ctxt,
     build_internal_underlying_enum_type_name(enum_name, is_anonymous,
 					     enum_size);
 
-  type_decl_sptr result(new type_decl(ctxt.env(), underlying_type_name,
+  type_decl_sptr result(new type_decl(rdr.env(), underlying_type_name,
 				      enum_size, enum_size, location()));
   result->set_is_anonymous(is_anonymous);
   result->set_is_artificial(true);
-  translation_unit_sptr tu = ctxt.cur_transl_unit();
+  translation_unit_sptr tu = rdr.cur_transl_unit();
   decl_base_sptr d = add_decl_to_scope(result, tu->get_global_scope().get());
   result = dynamic_pointer_cast<type_decl>(d);
   ABG_ASSERT(result);
@@ -12996,7 +12180,7 @@ build_enum_underlying_type(read_context& ctxt,
 
 /// Build an enum_type_decl from a DW_TAG_enumeration_type DIE.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @param die the DIE to read from.
 ///
@@ -13009,7 +12193,7 @@ build_enum_underlying_type(read_context& ctxt,
 ///
 /// @return the built enum_type_decl or NULL if it could not be built.
 static enum_type_decl_sptr
-build_enum_type(read_context&	ctxt,
+build_enum_type(reader&	rdr,
 		Dwarf_Die*	die,
 		scope_decl*	scope,
 		size_t		where_offset,
@@ -13025,7 +12209,7 @@ build_enum_type(read_context&	ctxt,
 
   string name, linkage_name;
   location loc;
-  die_loc_and_name(ctxt, die, loc, name, linkage_name);
+  die_loc_and_name(rdr, die, loc, name, linkage_name);
 
   bool is_anonymous = false;
   // If the enum is anonymous, let's give it a name.
@@ -13040,7 +12224,7 @@ build_enum_type(read_context&	ctxt,
 	name = build_internal_anonymous_die_name(name, s);
     }
 
-  bool use_odr = ctxt.odr_is_relevant(die);
+  bool use_odr = rdr.odr_is_relevant(die);
   // If the type has location, then associate it to its
   // representation.  This way, all occurences of types with the same
   // representation (name) and location can be later detected as being
@@ -13051,10 +12235,10 @@ build_enum_type(read_context&	ctxt,
       if (use_odr)
 	{
 	  if (enum_type_decl_sptr pre_existing_enum =
-	      is_enum_type(ctxt.lookup_artifact_from_die(die)))
+	      is_enum_type(rdr.lookup_artifact_from_die(die)))
 	    result = pre_existing_enum;
 	}
-      else if (corpus_sptr corp = ctxt.should_reuse_type_from_corpus_group())
+      else if (corpus_sptr corp = rdr.should_reuse_type_from_corpus_group())
 	{
 	  if (loc)
 	    result = lookup_enum_type_per_location(loc.expand(), *corp);
@@ -13062,14 +12246,14 @@ build_enum_type(read_context&	ctxt,
       else if (loc)
 	{
 	  if (enum_type_decl_sptr pre_existing_enum =
-	      is_enum_type(ctxt.lookup_artifact_from_die(die)))
+	      is_enum_type(rdr.lookup_artifact_from_die(die)))
 	    if (pre_existing_enum->get_location() == loc)
 	      result = pre_existing_enum;
 	}
 
       if (result)
 	{
-	  ctxt.associate_die_to_type(die, result, where_offset);
+	  rdr.associate_die_to_type(die, result, where_offset);
 	  return result;
 	}
     }
@@ -13095,10 +12279,10 @@ build_enum_type(read_context&	ctxt,
 
 	  string n, m;
 	  location l;
-	  die_loc_and_name(ctxt, &child, l, n, m);
+	  die_loc_and_name(rdr, &child, l, n, m);
 	  uint64_t val = 0;
 	  die_unsigned_constant_attribute(&child, DW_AT_const_value, val);
-	  enms.push_back(enum_type_decl::enumerator(ctxt.env(), n, val));
+	  enms.push_back(enum_type_decl::enumerator(n, val));
 	}
       while (dwarf_siblingof(&child, &child) == 0);
     }
@@ -13108,7 +12292,7 @@ build_enum_type(read_context&	ctxt,
   // sole purpose is to be passed to the constructor of the
   // enum_type_decl type.
   type_decl_sptr t =
-    build_enum_underlying_type(ctxt, name, size,
+    build_enum_underlying_type(rdr, name, size,
 			       enum_underlying_type_is_anonymous);
   t->set_is_declaration_only(is_declaration_only);
 
@@ -13116,9 +12300,9 @@ build_enum_type(read_context&	ctxt,
   result->set_is_anonymous(is_anonymous);
   result->set_is_declaration_only(is_declaration_only);
   result->set_is_artificial(is_artificial);
-  ctxt.associate_die_to_type(die, result, where_offset);
+  rdr.associate_die_to_type(die, result, where_offset);
 
-  ctxt.maybe_schedule_declaration_only_enum_for_resolution(result);
+  rdr.maybe_schedule_declaration_only_enum_for_resolution(result);
 
   return result;
 }
@@ -13135,12 +12319,12 @@ build_enum_type(read_context&	ctxt,
 ///
 /// @param klass the @ref class_or_union that @p f belongs to.
 ///
-/// @param ctxt the context used to read the ELF/DWARF information.
+/// @param rdr the context used to read the ELF/DWARF information.
 static void
 finish_member_function_reading(Dwarf_Die*			die,
 			       const function_decl_sptr&	f,
 			       const class_or_union_sptr	klass,
-			       read_context&			ctxt)
+			       reader&			rdr)
 {
   ABG_ASSERT(klass);
 
@@ -13237,7 +12421,7 @@ finish_member_function_reading(Dwarf_Die*			die,
       //
       // Let's thus schedule this function for a later fixup pass
       // (performed by
-      // read_context::fixup_functions_with_no_symbols()) that will
+      // reader::fixup_functions_with_no_symbols()) that will
       // set its underlying symbol.
       //
       // Note that if the underying symbol is encountered later in the
@@ -13246,7 +12430,7 @@ finish_member_function_reading(Dwarf_Die*			die,
       // de-schedule this function wrt fixup pass.
       Dwarf_Off die_offset = dwarf_dieoffset(die);
       die_function_decl_map_type &fns_with_no_symbol =
-	ctxt.die_function_decl_with_no_symbol_map();
+	rdr.die_function_decl_with_no_symbol_map();
       die_function_decl_map_type::const_iterator i =
 	fns_with_no_symbol.find(die_offset);
       if (i == fns_with_no_symbol.end())
@@ -13260,7 +12444,7 @@ finish_member_function_reading(Dwarf_Die*			die,
 /// then read those extra attributes and update the internal
 /// representation.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @param die the function DIE to consider.
 ///
@@ -13271,12 +12455,12 @@ finish_member_function_reading(Dwarf_Die*			die,
 ///
 /// @return the updated function  representation.
 static function_decl_sptr
-maybe_finish_function_decl_reading(read_context&		ctxt,
+maybe_finish_function_decl_reading(reader&		rdr,
 				   Dwarf_Die*			die,
 				   size_t			where_offset,
 				   const function_decl_sptr&	existing_fn)
 {
-  function_decl_sptr result = build_function_decl(ctxt, die,
+  function_decl_sptr result = build_function_decl(rdr, die,
 						  where_offset,
 						  existing_fn);
 
@@ -13305,7 +12489,7 @@ lookup_class_or_typedef_from_corpus(scope_decl* scope, const string& type_name)
 ///
 /// The type being looked for has the same name as a given DIE.
 ///
-/// @param ctxt the reading context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @param die the DIE which has the same name as the type we are
 /// looking for.
@@ -13317,7 +12501,7 @@ lookup_class_or_typedef_from_corpus(scope_decl* scope, const string& type_name)
 ///
 /// @return the type found.
 static type_base_sptr
-lookup_class_or_typedef_from_corpus(read_context& ctxt,
+lookup_class_or_typedef_from_corpus(reader& rdr,
 				    Dwarf_Die* die,
 				    bool called_for_public_decl,
 				    size_t where_offset)
@@ -13329,7 +12513,7 @@ lookup_class_or_typedef_from_corpus(read_context& ctxt,
   if (class_name.empty())
     return class_decl_sptr();
 
-  scope_decl_sptr scope = get_scope_for_die(ctxt, die,
+  scope_decl_sptr scope = get_scope_for_die(rdr, die,
 					    called_for_public_decl,
 					    where_offset);
   if (scope)
@@ -13392,7 +12576,7 @@ lookup_class_typedef_or_enum_type_from_corpus(Dwarf_Die* die,
 /// Test if a DIE represents a function that is a member of a given
 /// class type.
 ///
-/// @param ctxt the reading context.
+/// @param rdr the DWARF reader.
 ///
 /// @param function_die the DIE of the function to consider.
 ///
@@ -13404,11 +12588,11 @@ lookup_class_typedef_or_enum_type_from_corpus(Dwarf_Die* die,
 /// function of @p class_type, iff @p function_die is for a member
 /// function of @p class_type.
 static method_decl_sptr
-is_function_for_die_a_member_of_class(read_context& ctxt,
+is_function_for_die_a_member_of_class(reader& rdr,
 				      Dwarf_Die* function_die,
 				      const class_or_union_sptr& class_type)
 {
-  type_or_decl_base_sptr artifact = ctxt.lookup_artifact_from_die(function_die);
+  type_or_decl_base_sptr artifact = rdr.lookup_artifact_from_die(function_die);
 
   if (!artifact)
     return method_decl_sptr();
@@ -13443,7 +12627,7 @@ is_function_for_die_a_member_of_class(read_context& ctxt,
 /// new member function that is not already present in the class then
 /// add that new member function to the class.
 ///
-/// @param ctxt the reading context.
+/// @param rdr the DWARF reader.
 ///
 /// @param function_die the DIE of the potential member function to
 /// consider.
@@ -13457,17 +12641,17 @@ is_function_for_die_a_member_of_class(read_context& ctxt,
 ///
 /// @return the method decl representing the member function.
 static method_decl_sptr
-add_or_update_member_function(read_context& ctxt,
+add_or_update_member_function(reader& rdr,
 			      Dwarf_Die* function_die,
 			      const class_or_union_sptr& class_type,
 			      bool called_from_public_decl,
 			      size_t where_offset)
 {
   method_decl_sptr method =
-    is_function_for_die_a_member_of_class(ctxt, function_die, class_type);
+    is_function_for_die_a_member_of_class(rdr, function_die, class_type);
 
   if (!method)
-    method = is_method_decl(build_ir_node_from_die(ctxt, function_die,
+    method = is_method_decl(build_ir_node_from_die(rdr, function_die,
 						   class_type.get(),
 						   called_from_public_decl,
 						   where_offset));
@@ -13476,7 +12660,7 @@ add_or_update_member_function(read_context& ctxt,
 
   finish_member_function_reading(function_die,
 				 is_function_decl(method),
-				 class_type, ctxt);
+				 class_type, rdr);
   return method;
 }
 
@@ -13491,7 +12675,7 @@ add_or_update_member_function(read_context& ctxt,
 /// class_decl node with data members, member functions and other
 /// properties coming from the DIE.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param die the DIE to read information from.  Must be either a
 /// DW_TAG_structure_type or a DW_TAG_class_type.
@@ -13517,7 +12701,7 @@ add_or_update_member_function(read_context& ctxt,
 ///
 /// @return the resulting class_type.
 static class_decl_sptr
-add_or_update_class_type(read_context&	 ctxt,
+add_or_update_class_type(reader&	 rdr,
 			 Dwarf_Die*	 die,
 			 scope_decl*	 scope,
 			 bool		 is_struct,
@@ -13530,7 +12714,7 @@ add_or_update_class_type(read_context&	 ctxt,
   if (!die)
     return result;
 
-  const die_source source = ctxt.get_die_source(die);
+  const die_source source = rdr.get_die_source(die);
 
   unsigned tag = dwarf_tag(die);
 
@@ -13539,8 +12723,8 @@ add_or_update_class_type(read_context&	 ctxt,
 
   {
     die_class_or_union_map_type::const_iterator i =
-      ctxt.die_wip_classes_map(source).find(dwarf_dieoffset(die));
-    if (i != ctxt.die_wip_classes_map(source).end())
+      rdr.die_wip_classes_map(source).find(dwarf_dieoffset(die));
+    if (i != rdr.die_wip_classes_map(source).end())
       {
 	class_decl_sptr class_type = is_class_type(i->second);
 	ABG_ASSERT(class_type);
@@ -13550,7 +12734,7 @@ add_or_update_class_type(read_context&	 ctxt,
 
   string name, linkage_name;
   location loc;
-  die_loc_and_name(ctxt, die, loc, name, linkage_name);
+  die_loc_and_name(rdr, die, loc, name, linkage_name);
 
   bool is_anonymous = false;
   if (name.empty())
@@ -13568,7 +12752,7 @@ add_or_update_class_type(read_context&	 ctxt,
 
   if (!is_anonymous)
     {
-      if (corpus_sptr corp = ctxt.should_reuse_type_from_corpus_group())
+      if (corpus_sptr corp = rdr.should_reuse_type_from_corpus_group())
 	{
 	  if (loc)
 	    // TODO: if there is only one class defined in the corpus
@@ -13588,7 +12772,7 @@ add_or_update_class_type(read_context&	 ctxt,
 		  || (!result->get_is_declaration_only()
 		      && is_declaration_only)))
 	    {
-	      ctxt.associate_die_to_type(die, result, where_offset);
+	      rdr.associate_die_to_type(die, result, where_offset);
 	      return result;
 	    }
 	  else
@@ -13606,7 +12790,7 @@ add_or_update_class_type(read_context&	 ctxt,
   // when they do have a naming typedef.
   if (!is_anonymous)
     if (class_decl_sptr pre_existing_class =
-	is_class_type(ctxt.lookup_type_artifact_from_die(die)))
+	is_class_type(rdr.lookup_type_artifact_from_die(die)))
       klass = pre_existing_class;
 
   uint64_t size = 0;
@@ -13628,7 +12812,7 @@ add_or_update_class_type(read_context&	 ctxt,
     }
   else
     {
-      result.reset(new class_decl(ctxt.env(), name, size,
+      result.reset(new class_decl(rdr.env(), name, size,
 				  /*alignment=*/0, is_struct, loc,
 				  decl_base::VISIBILITY_DEFAULT,
 				  is_anonymous));
@@ -13670,16 +12854,16 @@ add_or_update_class_type(read_context&	 ctxt,
 
   result->set_is_artificial(is_artificial);
 
-  ctxt.associate_die_to_type(die, result, where_offset);
+  rdr.associate_die_to_type(die, result, where_offset);
 
-  ctxt.maybe_schedule_declaration_only_class_for_resolution(result);
+  rdr.maybe_schedule_declaration_only_class_for_resolution(result);
 
   if (!has_child)
     // TODO: set the access specifier for the declaration-only class
     // here.
     return result;
 
-  ctxt.die_wip_classes_map(source)[dwarf_dieoffset(die)] = result;
+  rdr.die_wip_classes_map(source)[dwarf_dieoffset(die)] = result;
 
   bool is_incomplete_type = false;
   if (is_declaration_only && size == 0 && has_child)
@@ -13693,13 +12877,13 @@ add_or_update_class_type(read_context&	 ctxt,
     // referred to by a pointer.  If we later encounter a definition
     // for this decl-only class type, then this decl-only class will
     // be resolved to it by the code in
-    // read_context::resolve_declaration_only_classes.
+    // reader::resolve_declaration_only_classes.
     is_incomplete_type = true;
 
   scope_decl_sptr scop =
     dynamic_pointer_cast<scope_decl>(res);
   ABG_ASSERT(scop);
-  ctxt.scope_stack().push(scop.get());
+  rdr.scope_stack().push(scop.get());
 
   if (has_child && !is_incomplete_type)
     {
@@ -13722,12 +12906,12 @@ add_or_update_class_type(read_context&	 ctxt,
 
 	      type_base_sptr base_type;
 	      if (!(base_type =
-		    lookup_class_or_typedef_from_corpus(ctxt, &type_die,
+		    lookup_class_or_typedef_from_corpus(rdr, &type_die,
 							called_from_public_decl,
 							where_offset)))
 		{
 		  base_type =
-		    is_type(build_ir_node_from_die(ctxt, &type_die,
+		    is_type(build_ir_node_from_die(rdr, &type_die,
 						   called_from_public_decl,
 						   where_offset));
 		}
@@ -13747,14 +12931,14 @@ add_or_update_class_type(read_context&	 ctxt,
 	      bool is_virt= die_is_virtual(&child);
 	      int64_t offset = 0;
 	      bool is_offset_present =
-		die_member_offset(ctxt, &child, offset);
+		die_member_offset(rdr, &child, offset);
 
 	      class_decl::base_spec_sptr base(new class_decl::base_spec
 					      (b, access,
 					       is_offset_present ? offset : -1,
 					       is_virt));
 	      if (b->get_is_declaration_only())
-		ABG_ASSERT(ctxt.is_decl_only_class_scheduled_for_resolution(b));
+		ABG_ASSERT(rdr.is_decl_only_class_scheduled_for_resolution(b));
 	      if (result->find_base_class(b->get_qualified_name()))
 		continue;
 	      result->add_base_specifier(base);
@@ -13769,7 +12953,7 @@ add_or_update_class_type(read_context&	 ctxt,
 
 	      string n, m;
 	      location loc;
-	      die_loc_and_name(ctxt, &child, loc, n, m);
+	      die_loc_and_name(rdr, &child, loc, n, m);
 	      /// For now, we skip the hidden vtable pointer.
 	      /// Currently, we're looking for a member starting with
 	      /// "_vptr[^0-9a-zA-Z_]", which is what Clang and GCC
@@ -13786,19 +12970,19 @@ add_or_update_class_type(read_context&	 ctxt,
 		continue;
 
 	      int64_t offset_in_bits = 0;
-	      bool is_laid_out = die_member_offset(ctxt, &child,
+	      bool is_laid_out = die_member_offset(rdr, &child,
 						   offset_in_bits);
 	      // For now, is_static == !is_laid_out.  When we have
 	      // templates, we'll try to be more specific.  For now,
 	      // this approximation should do OK.
 	      bool is_static = !is_laid_out;
 
-	      if (is_static && variable_is_suppressed(ctxt,
+	      if (is_static && variable_is_suppressed(rdr,
 						      result.get(),
 						      &child))
 		continue;
 
-	      decl_base_sptr ty = is_decl(build_ir_node_from_die(ctxt, &type_die,
+	      decl_base_sptr ty = is_decl(build_ir_node_from_die(rdr, &type_die,
 								 called_from_public_decl,
 								 where_offset));
 	      type_base_sptr t = is_type(ty);
@@ -13834,18 +13018,18 @@ add_or_update_class_type(read_context&	 ctxt,
 	      result->add_data_member(dm, access, is_laid_out,
 				      is_static, offset_in_bits);
 	      ABG_ASSERT(has_scope(dm));
-	      ctxt.associate_die_to_decl(&child, dm, where_offset,
+	      rdr.associate_die_to_decl(&child, dm, where_offset,
 					 /*associate_by_repr=*/false);
 	    }
 	  // Handle member functions;
 	  else if (tag == DW_TAG_subprogram)
 	    {
 	      decl_base_sptr r =
-		add_or_update_member_function(ctxt, &child, result,
+		add_or_update_member_function(rdr, &child, result,
 					      called_from_public_decl,
 					      where_offset);
 	      if (function_decl_sptr f = is_function_decl(r))
-		ctxt.associate_die_to_decl(&child, f, where_offset,
+		rdr.associate_die_to_decl(&child, f, where_offset,
 					   /*associate_by_repr=*/true);
 	    }
 	  // Handle member types
@@ -13875,34 +13059,34 @@ add_or_update_class_type(read_context&	 ctxt,
 		   && !lookup_class_typedef_or_enum_type_from_corpus
 		   (&child, anonymous_member_type_index, result.get()))
 		  || !result->find_member_type(die_name(&child)))
-		build_ir_node_from_die(ctxt, &child, result.get(),
+		build_ir_node_from_die(rdr, &child, result.get(),
 				       called_from_public_decl,
 				       where_offset);
 	    }
 	} while (dwarf_siblingof(&child, &child) == 0);
     }
 
-  ctxt.scope_stack().pop();
+  rdr.scope_stack().pop();
 
   {
     die_class_or_union_map_type::const_iterator i =
-      ctxt.die_wip_classes_map(source).find(dwarf_dieoffset(die));
-    if (i != ctxt.die_wip_classes_map(source).end())
+      rdr.die_wip_classes_map(source).find(dwarf_dieoffset(die));
+    if (i != rdr.die_wip_classes_map(source).end())
       {
 	if (is_member_type(i->second))
 	  set_member_access_specifier(res,
 				      get_member_access_specifier(i->second));
-	ctxt.die_wip_classes_map(source).erase(i);
+	rdr.die_wip_classes_map(source).erase(i);
       }
   }
 
-  ctxt.maybe_schedule_declaration_only_class_for_resolution(result);
+  rdr.maybe_schedule_declaration_only_class_for_resolution(result);
   return result;
 }
 
 /// Build an @ref union_decl from a DW_TAG_union_type DIE.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @param die the DIE to read from.
 ///
@@ -13925,7 +13109,7 @@ add_or_update_class_type(read_context&	 ctxt,
 ///
 /// @return the resulting @ref union_decl type.
 static union_decl_sptr
-add_or_update_union_type(read_context&	 ctxt,
+add_or_update_union_type(reader&	 rdr,
 			 Dwarf_Die*	 die,
 			 scope_decl*	 scope,
 			 union_decl_sptr union_type,
@@ -13942,11 +13126,11 @@ add_or_update_union_type(read_context&	 ctxt,
   if (tag != DW_TAG_union_type)
     return result;
 
-  const die_source source = ctxt.get_die_source(die);
+  const die_source source = rdr.get_die_source(die);
   {
     die_class_or_union_map_type::const_iterator i =
-      ctxt.die_wip_classes_map(source).find(dwarf_dieoffset(die));
-    if (i != ctxt.die_wip_classes_map(source).end())
+      rdr.die_wip_classes_map(source).find(dwarf_dieoffset(die));
+    if (i != rdr.die_wip_classes_map(source).end())
       {
 	union_decl_sptr u = is_union_type(i->second);
 	ABG_ASSERT(u);
@@ -13956,7 +13140,7 @@ add_or_update_union_type(read_context&	 ctxt,
 
   string name, linkage_name;
   location loc;
-  die_loc_and_name(ctxt, die, loc, name, linkage_name);
+  die_loc_and_name(rdr, die, loc, name, linkage_name);
 
   bool is_anonymous = false;
   if (name.empty())
@@ -13979,7 +13163,7 @@ add_or_update_union_type(read_context&	 ctxt,
 
   if (!is_anonymous)
     {
-      if (corpus_sptr corp = ctxt.should_reuse_type_from_corpus_group())
+      if (corpus_sptr corp = rdr.should_reuse_type_from_corpus_group())
 	{
 	  if (loc)
 	    result = lookup_union_type_per_location(loc.expand(), *corp);
@@ -13988,7 +13172,7 @@ add_or_update_union_type(read_context&	 ctxt,
 
 	  if (result)
 	    {
-	      ctxt.associate_die_to_type(die, result, where_offset);
+	      rdr.associate_die_to_type(die, result, where_offset);
 	      return result;
 	    }
 	}
@@ -14001,7 +13185,7 @@ add_or_update_union_type(read_context&	 ctxt,
   // a naming typedef.
   if (!is_anonymous)
     if (union_decl_sptr pre_existing_union =
-	is_union_type(ctxt.lookup_artifact_from_die(die)))
+	is_union_type(rdr.lookup_artifact_from_die(die)))
       union_type = pre_existing_union;
 
   uint64_t size = 0;
@@ -14015,7 +13199,7 @@ add_or_update_union_type(read_context&	 ctxt,
     }
   else
     {
-      result.reset(new union_decl(ctxt.env(), name, size, loc,
+      result.reset(new union_decl(rdr.env(), name, size, loc,
 				  decl_base::VISIBILITY_DEFAULT,
 				  is_anonymous));
       if (is_declaration_only)
@@ -14032,23 +13216,23 @@ add_or_update_union_type(read_context&	 ctxt,
 
   result->set_is_artificial(is_artificial);
 
-  ctxt.associate_die_to_type(die, result, where_offset);
+  rdr.associate_die_to_type(die, result, where_offset);
 
   // TODO: maybe schedule declaration-only union for result like we do
   // for classes:
-  // ctxt.maybe_schedule_declaration_only_class_for_resolution(result);
+  // rdr.maybe_schedule_declaration_only_class_for_resolution(result);
 
   Dwarf_Die child;
   bool has_child = (dwarf_child(die, &child) == 0);
   if (!has_child)
     return result;
 
-  ctxt.die_wip_classes_map(source)[dwarf_dieoffset(die)] = result;
+  rdr.die_wip_classes_map(source)[dwarf_dieoffset(die)] = result;
 
   scope_decl_sptr scop =
     dynamic_pointer_cast<scope_decl>(result);
   ABG_ASSERT(scop);
-  ctxt.scope_stack().push(scop.get());
+  rdr.scope_stack().push(scop.get());
 
   if (has_child)
     {
@@ -14064,7 +13248,7 @@ add_or_update_union_type(read_context&	 ctxt,
 
 	      string n, m;
 	      location loc;
-	      die_loc_and_name(ctxt, &child, loc, n, m);
+	      die_loc_and_name(rdr, &child, loc, n, m);
 
 	      // Because we can be updating an existing union, let's
 	      // make sure we don't already have a member of the same
@@ -14075,7 +13259,7 @@ add_or_update_union_type(read_context&	 ctxt,
 
 	      ssize_t offset_in_bits = 0;
 	      decl_base_sptr ty =
-		is_decl(build_ir_node_from_die(ctxt, &type_die,
+		is_decl(build_ir_node_from_die(rdr, &type_die,
 					       called_from_public_decl,
 					       where_offset));
 	      type_base_sptr t = is_type(ty);
@@ -14101,14 +13285,14 @@ add_or_update_union_type(read_context&	 ctxt,
 				      /*is_static=*/false,
 				      offset_in_bits);
 	      ABG_ASSERT(has_scope(dm));
-	      ctxt.associate_die_to_decl(&child, dm, where_offset,
+	      rdr.associate_die_to_decl(&child, dm, where_offset,
 					 /*associate_by_repr=*/false);
 	    }
 	  // Handle member functions;
 	  else if (tag == DW_TAG_subprogram)
 	    {
 	      decl_base_sptr r =
-		is_decl(build_ir_node_from_die(ctxt, &child,
+		is_decl(build_ir_node_from_die(rdr, &child,
 					       result.get(),
 					       called_from_public_decl,
 					       where_offset));
@@ -14118,31 +13302,31 @@ add_or_update_union_type(read_context&	 ctxt,
 	      function_decl_sptr f = dynamic_pointer_cast<function_decl>(r);
 	      ABG_ASSERT(f);
 
-	      finish_member_function_reading(&child, f, result, ctxt);
+	      finish_member_function_reading(&child, f, result, rdr);
 
-	      ctxt.associate_die_to_decl(&child, f, where_offset,
+	      rdr.associate_die_to_decl(&child, f, where_offset,
 					 /*associate_by_repr=*/false);
 	    }
 	  // Handle member types
 	  else if (die_is_type(&child))
 	    decl_base_sptr td =
-	      is_decl(build_ir_node_from_die(ctxt, &child, result.get(),
+	      is_decl(build_ir_node_from_die(rdr, &child, result.get(),
 					     called_from_public_decl,
 					     where_offset));
 	} while (dwarf_siblingof(&child, &child) == 0);
     }
 
-  ctxt.scope_stack().pop();
+  rdr.scope_stack().pop();
 
   {
     die_class_or_union_map_type::const_iterator i =
-      ctxt.die_wip_classes_map(source).find(dwarf_dieoffset(die));
-    if (i != ctxt.die_wip_classes_map(source).end())
+      rdr.die_wip_classes_map(source).find(dwarf_dieoffset(die));
+    if (i != rdr.die_wip_classes_map(source).end())
       {
 	if (is_member_type(i->second))
 	  set_member_access_specifier(result,
 				      get_member_access_specifier(i->second));
-	ctxt.die_wip_classes_map(source).erase(i);
+	rdr.die_wip_classes_map(source).erase(i);
       }
   }
 
@@ -14152,7 +13336,7 @@ add_or_update_union_type(read_context&	 ctxt,
 /// build a qualified type from a DW_TAG_const_type,
 /// DW_TAG_volatile_type or DW_TAG_restrict_type DIE.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param die the input DIE to read from.
 ///
@@ -14167,7 +13351,7 @@ add_or_update_union_type(read_context&	 ctxt,
 ///
 /// @return the resulting qualified_type_def.
 static type_base_sptr
-build_qualified_type(read_context&	ctxt,
+build_qualified_type(reader&	rdr,
 		     Dwarf_Die*	die,
 		     bool		called_from_public_decl,
 		     size_t		where_offset)
@@ -14189,10 +13373,10 @@ build_qualified_type(read_context&	ctxt,
     // So, if no DW_AT_type is present, then this means (if we are
     // looking at a debug info emitted by GCC) that we are looking
     // at a qualified void type.
-    utype_decl = build_ir_node_for_void_type(ctxt);
+    utype_decl = build_ir_node_for_void_type(rdr);
 
   if (!utype_decl)
-    utype_decl = is_decl(build_ir_node_from_die(ctxt, &underlying_type_die,
+    utype_decl = is_decl(build_ir_node_from_die(rdr, &underlying_type_die,
 						called_from_public_decl,
 						where_offset));
   if (!utype_decl)
@@ -14200,10 +13384,10 @@ build_qualified_type(read_context&	ctxt,
 
   // The call to build_ir_node_from_die() could have triggered the
   // creation of the type for this DIE.  In that case, just return it.
-  if (type_base_sptr t = ctxt.lookup_type_from_die(die))
+  if (type_base_sptr t = rdr.lookup_type_from_die(die))
     {
       result = t;
-      ctxt.associate_die_to_type(die, result, where_offset);
+      rdr.associate_die_to_type(die, result, where_offset);
       return result;
     }
 
@@ -14223,7 +13407,7 @@ build_qualified_type(read_context&	ctxt,
   if (!result)
     result.reset(new qualified_type_def(utype, qual, location()));
 
-  ctxt.associate_die_to_type(die, result, where_offset);
+  rdr.associate_die_to_type(die, result, where_offset);
 
   return result;
 }
@@ -14239,22 +13423,22 @@ build_qualified_type(read_context&	ctxt,
 ///
 /// @param t the type node to be scheduled for canonicalization.
 ///
-/// @param ctxt the contexter of the reader to use.
+/// @param rdr the DWARF reader to use.
 static void
 schedule_array_tree_for_late_canonicalization(const type_base_sptr& t,
-					      read_context &ctxt)
+					      reader &rdr)
 {
   if (typedef_decl_sptr type = is_typedef(t))
     {
       schedule_array_tree_for_late_canonicalization(type->get_underlying_type(),
-						    ctxt);
-      ctxt.schedule_type_for_late_canonicalization(t);
+						    rdr);
+      rdr.schedule_type_for_late_canonicalization(t);
     }
   else if (qualified_type_def_sptr type = is_qualified_type(t))
     {
       schedule_array_tree_for_late_canonicalization(type->get_underlying_type(),
-						    ctxt);
-      ctxt.schedule_type_for_late_canonicalization(t);
+						    rdr);
+      rdr.schedule_type_for_late_canonicalization(t);
     }
   else if (array_type_def_sptr type = is_array_type(t))
     {
@@ -14264,13 +13448,13 @@ schedule_array_tree_for_late_canonicalization(const type_base_sptr& t,
 	   ++i)
 	{
 	  if (!(*i)->get_scope())
-	    add_decl_to_scope(*i, ctxt.cur_transl_unit()->get_global_scope());
-	  ctxt.schedule_type_for_late_canonicalization(*i);
+	    add_decl_to_scope(*i, rdr.cur_transl_unit()->get_global_scope());
+	  rdr.schedule_type_for_late_canonicalization(*i);
 
 	}
       schedule_array_tree_for_late_canonicalization(type->get_element_type(),
-						    ctxt);
-      ctxt.schedule_type_for_late_canonicalization(type);
+						    rdr);
+      rdr.schedule_type_for_late_canonicalization(type);
     }
 }
 
@@ -14286,12 +13470,12 @@ schedule_array_tree_for_late_canonicalization(const type_base_sptr& t,
 ///
 /// @param t the type to strip const qualification from.
 ///
-/// @param ctxt the @ref read_context to use.
+/// @param rdr the @ref reader to use.
 ///
 /// @return the stripped type or just return @p t.
 static decl_base_sptr
 maybe_strip_qualification(const qualified_type_def_sptr t,
-			  read_context &ctxt)
+			  reader &rdr)
 {
   if (!t)
     return t;
@@ -14313,7 +13497,7 @@ maybe_strip_qualification(const qualified_type_def_sptr t,
 	  scope = array->get_scope();
 	  ABG_ASSERT(scope);
 	  array = is_array_type(clone_array_tree(array));
-	  schedule_array_tree_for_late_canonicalization(array, ctxt);
+	  schedule_array_tree_for_late_canonicalization(array, rdr);
 	  add_decl_to_scope(array, scope);
 	  t->set_underlying_type(array);
 	  u = t->get_underlying_type();
@@ -14324,7 +13508,7 @@ maybe_strip_qualification(const qualified_type_def_sptr t,
 	  ABG_ASSERT(scope);
 	  typedef_decl_sptr typdef =
 	    is_typedef(clone_array_tree(is_typedef(u)));
-	  schedule_array_tree_for_late_canonicalization(typdef, ctxt);
+	  schedule_array_tree_for_late_canonicalization(typdef, rdr);
 	  ABG_ASSERT(typdef);
 	  add_decl_to_scope(typdef, scope);
 	  t->set_underlying_type(typdef);
@@ -14358,7 +13542,7 @@ maybe_strip_qualification(const qualified_type_def_sptr t,
 	  strip_redundant_quals_from_underyling_types(qual_type);
 	  add_decl_to_scope(qual_type, is_decl(element_type)->get_scope());
 	  array->set_element_type(qual_type);
-	  ctxt.schedule_type_for_late_canonicalization(is_type(qual_type));
+	  rdr.schedule_type_for_late_canonicalization(is_type(qual_type));
 	  result = is_decl(u);
 	}
     }
@@ -14368,7 +13552,7 @@ maybe_strip_qualification(const qualified_type_def_sptr t,
 
 /// Build a pointer type from a DW_TAG_pointer_type DIE.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param die the DIE to read information from.
 ///
@@ -14383,7 +13567,7 @@ maybe_strip_qualification(const qualified_type_def_sptr t,
 ///
 /// @return the resulting pointer to pointer_type_def.
 static pointer_type_def_sptr
-build_pointer_type_def(read_context&	ctxt,
+build_pointer_type_def(reader&	rdr,
 		       Dwarf_Die*	die,
 		       bool		called_from_public_decl,
 		       size_t		where_offset)
@@ -14403,12 +13587,12 @@ build_pointer_type_def(read_context&	ctxt,
   if (!die_die_attribute(die, DW_AT_type, underlying_type_die))
     // If the DW_AT_type attribute is missing, that means we are
     // looking at a pointer to "void".
-    utype_decl = build_ir_node_for_void_type(ctxt);
+    utype_decl = build_ir_node_for_void_type(rdr);
   else
     has_underlying_type_die = true;
 
   if (!utype_decl && has_underlying_type_die)
-    utype_decl = build_ir_node_from_die(ctxt, &underlying_type_die,
+    utype_decl = build_ir_node_from_die(rdr, &underlying_type_die,
 					called_from_public_decl,
 					where_offset);
   if (!utype_decl)
@@ -14416,7 +13600,7 @@ build_pointer_type_def(read_context&	ctxt,
 
   // The call to build_ir_node_from_die() could have triggered the
   // creation of the type for this DIE.  In that case, just return it.
-  if (type_base_sptr t = ctxt.lookup_type_from_die(die))
+  if (type_base_sptr t = rdr.lookup_type_from_die(die))
     {
       result = is_pointer_type(t);
       ABG_ASSERT(result);
@@ -14429,7 +13613,7 @@ build_pointer_type_def(read_context&	ctxt,
   // if the DIE for the pointer type doesn't have a byte_size
   // attribute then we assume the size of the pointer is the address
   // size of the current translation unit.
-  uint64_t size = ctxt.cur_transl_unit()->get_address_size();
+  uint64_t size = rdr.cur_transl_unit()->get_address_size();
   if (die_unsigned_constant_attribute(die, DW_AT_byte_size, size))
     // The size as expressed by DW_AT_byte_size is in byte, so let's
     // convert it to bits.
@@ -14437,19 +13621,19 @@ build_pointer_type_def(read_context&	ctxt,
 
   // And the size of the pointer must be the same as the address size
   // of the current translation unit.
-  ABG_ASSERT((size_t) ctxt.cur_transl_unit()->get_address_size() == size);
+  ABG_ASSERT((size_t) rdr.cur_transl_unit()->get_address_size() == size);
 
   result.reset(new pointer_type_def(utype, size, /*alignment=*/0, location()));
   ABG_ASSERT(result->get_pointed_to_type());
 
-  ctxt.associate_die_to_type(die, result, where_offset);
+  rdr.associate_die_to_type(die, result, where_offset);
   return result;
 }
 
 /// Build a reference type from either a DW_TAG_reference_type or
 /// DW_TAG_rvalue_reference_type DIE.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param die the DIE to read from.
 ///
@@ -14464,7 +13648,7 @@ build_pointer_type_def(read_context&	ctxt,
 ///
 /// @return a pointer to the resulting reference_type_def.
 static reference_type_def_sptr
-build_reference_type(read_context&	ctxt,
+build_reference_type(reader&	rdr,
 		     Dwarf_Die*	die,
 		     bool		called_from_public_decl,
 		     size_t		where_offset)
@@ -14484,7 +13668,7 @@ build_reference_type(read_context&	ctxt,
     return result;
 
   type_or_decl_base_sptr utype_decl =
-    build_ir_node_from_die(ctxt, &underlying_type_die,
+    build_ir_node_from_die(rdr, &underlying_type_die,
 			   called_from_public_decl,
 			   where_offset);
   if (!utype_decl)
@@ -14492,7 +13676,7 @@ build_reference_type(read_context&	ctxt,
 
   // The call to build_ir_node_from_die() could have triggered the
   // creation of the type for this DIE.  In that case, just return it.
-  if (type_base_sptr t = ctxt.lookup_type_from_die(die))
+  if (type_base_sptr t = rdr.lookup_type_from_die(die))
     {
       result = is_reference_type(t);
       ABG_ASSERT(result);
@@ -14505,29 +13689,29 @@ build_reference_type(read_context&	ctxt,
   // if the DIE for the reference type doesn't have a byte_size
   // attribute then we assume the size of the reference is the address
   // size of the current translation unit.
-  uint64_t size = ctxt.cur_transl_unit()->get_address_size();
+  uint64_t size = rdr.cur_transl_unit()->get_address_size();
   if (die_unsigned_constant_attribute(die, DW_AT_byte_size, size))
     size *= 8;
 
   // And the size of the pointer must be the same as the address size
   // of the current translation unit.
-  ABG_ASSERT((size_t) ctxt.cur_transl_unit()->get_address_size() == size);
+  ABG_ASSERT((size_t) rdr.cur_transl_unit()->get_address_size() == size);
 
   bool is_lvalue = tag == DW_TAG_reference_type;
 
   result.reset(new reference_type_def(utype, is_lvalue, size,
 				      /*alignment=*/0,
 				      location()));
-  if (corpus_sptr corp = ctxt.current_corpus())
+  if (corpus_sptr corp = rdr.corpus())
     if (reference_type_def_sptr t = lookup_reference_type(*result, *corp))
       result = t;
-  ctxt.associate_die_to_type(die, result, where_offset);
+  rdr.associate_die_to_type(die, result, where_offset);
   return result;
 }
 
 /// Build a subroutine type from a DW_TAG_subroutine_type DIE.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param die the DIE to read from.
 ///
@@ -14542,7 +13726,7 @@ build_reference_type(read_context&	ctxt,
 ///
 /// @return a pointer to the resulting function_type_sptr.
 static function_type_sptr
-build_function_type(read_context&	ctxt,
+build_function_type(reader&	rdr,
 		    Dwarf_Die*		die,
 		    class_or_union_sptr is_method,
 		    size_t		where_offset)
@@ -14555,12 +13739,12 @@ build_function_type(read_context&	ctxt,
   ABG_ASSERT(dwarf_tag(die) == DW_TAG_subroutine_type
 	     || dwarf_tag(die) == DW_TAG_subprogram);
 
-  const die_source source = ctxt.get_die_source(die);
+  const die_source source = rdr.get_die_source(die);
 
   {
     size_t off = dwarf_dieoffset(die);
-    auto i = ctxt.die_wip_function_types_map(source).find(off);
-    if (i != ctxt.die_wip_function_types_map(source).end())
+    auto i = rdr.die_wip_function_types_map(source).find(off);
+    if (i != rdr.die_wip_function_types_map(source).end())
       {
 	function_type_sptr fn_type = is_function_type(i->second);
 	ABG_ASSERT(fn_type);
@@ -14570,21 +13754,21 @@ build_function_type(read_context&	ctxt,
 
   decl_base_sptr type_decl;
 
-  translation_unit_sptr tu = ctxt.cur_transl_unit();
+  translation_unit_sptr tu = rdr.cur_transl_unit();
   ABG_ASSERT(tu);
 
   /// If, inside the current translation unit, we've already seen a
   /// function type with the same text representation, then reuse that
   /// one instead.
-  if (type_base_sptr t = ctxt.lookup_fn_type_from_die_repr_per_tu(die))
+  if (type_base_sptr t = rdr.lookup_fn_type_from_die_repr_per_tu(die))
     {
       result = is_function_type(t);
       ABG_ASSERT(result);
-      ctxt.associate_die_to_type(die, result, where_offset);
+      rdr.associate_die_to_type(die, result, where_offset);
       return result;
     }
 
-  bool odr_is_relevant = ctxt.odr_is_relevant(die);
+  bool odr_is_relevant = rdr.odr_is_relevant(die);
   if (odr_is_relevant)
     {
       // So we can rely on the One Definition Rule to say that if
@@ -14595,9 +13779,9 @@ build_function_type(read_context&	ctxt,
       // representation as the function type 'die', then it's the same
       // type as the one denoted by 'die'.
       if (function_type_sptr fn_type =
-	  is_function_type(ctxt.lookup_type_artifact_from_die(die)))
+	  is_function_type(rdr.lookup_type_artifact_from_die(die)))
 	{
-	  ctxt.associate_die_to_type(die, fn_type, where_offset);
+	  rdr.associate_die_to_type(die, fn_type, where_offset);
 	  return fn_type;
 	}
     }
@@ -14610,7 +13794,7 @@ build_function_type(read_context&	ctxt,
   Dwarf_Die object_pointer_die;
   Dwarf_Die class_type_die;
   bool has_this_parm_die =
-    die_function_type_is_method_type(ctxt, die, where_offset,
+    die_function_type_is_method_type(rdr, die, where_offset,
 				     object_pointer_die,
 				     class_type_die,
 				     is_static);
@@ -14628,7 +13812,7 @@ build_function_type(read_context&	ctxt,
 	  // by DIE was *NOT* a member function.  But now we know it's
 	  // a member function.  Let's take that into account.
 	  class_or_union_sptr klass_type =
-	    is_class_or_union_type(build_ir_node_from_die(ctxt, &class_type_die,
+	    is_class_or_union_type(build_ir_node_from_die(rdr, &class_type_die,
 							  /*called_from_pub_decl=*/true,
 							  where_offset));
 	  ABG_ASSERT(klass_type);
@@ -14645,20 +13829,20 @@ build_function_type(read_context&	ctxt,
 	       ? new method_type(is_method, is_const,
 				 tu->get_address_size(),
 				 /*alignment=*/0)
-	       : new function_type(ctxt.env(), tu->get_address_size(),
+	       : new function_type(rdr.env(), tu->get_address_size(),
 				   /*alignment=*/0));
-  ctxt.associate_die_to_type(die, result, where_offset);
-  ctxt.die_wip_function_types_map(source)[dwarf_dieoffset(die)] = result;
+  rdr.associate_die_to_type(die, result, where_offset);
+  rdr.die_wip_function_types_map(source)[dwarf_dieoffset(die)] = result;
 
   type_base_sptr return_type;
   Dwarf_Die ret_type_die;
   if (die_die_attribute(die, DW_AT_type, ret_type_die))
     return_type =
-      is_type(build_ir_node_from_die(ctxt, &ret_type_die,
+      is_type(build_ir_node_from_die(rdr, &ret_type_die,
 				     /*called_from_public_decl=*/true,
 				     where_offset));
   if (!return_type)
-    return_type = is_type(build_ir_node_for_void_type(ctxt));
+    return_type = is_type(build_ir_node_for_void_type(rdr));
   result->set_return_type(return_type);
 
   Dwarf_Die child;
@@ -14673,7 +13857,7 @@ build_function_type(read_context&	ctxt,
 	    // This is a "normal" function parameter.
 	    string name, linkage_name;
 	    location loc;
-	    die_loc_and_name(ctxt, &child, loc, name, linkage_name);
+	    die_loc_and_name(rdr, &child, loc, name, linkage_name);
 	    if (!tools_utils::string_is_ascii_identifier(name))
 	      // Sometimes, bogus compiler emit names that are
 	      // non-ascii garbage.  Let's just ditch that for now.
@@ -14683,7 +13867,7 @@ build_function_type(read_context&	ctxt,
 	    Dwarf_Die parm_type_die;
 	    if (die_die_attribute(&child, DW_AT_type, parm_type_die))
 	      parm_type =
-		is_type(build_ir_node_from_die(ctxt, &parm_type_die,
+		is_type(build_ir_node_from_die(rdr, &parm_type_die,
 					       /*called_from_public_decl=*/true,
 					       where_offset));
 	    if (!parm_type)
@@ -14698,10 +13882,9 @@ build_function_type(read_context&	ctxt,
 	  {
 	    // This is a variadic function parameter.
 	    bool is_artificial = die_is_artificial(&child);
-	    ir::environment* env = ctxt.env();
-	    ABG_ASSERT(env);
+
 	    type_base_sptr parm_type =
-	      is_type(build_ir_node_for_variadic_parameter_type(ctxt));
+	      is_type(build_ir_node_for_variadic_parameter_type(rdr));
 	    function_decl::parameter_sptr p
 	      (new function_decl::parameter(parm_type,
 					    /*name=*/"",
@@ -14726,23 +13909,23 @@ build_function_type(read_context&	ctxt,
 
   result->set_is_artificial(true);
 
-  ctxt.associate_die_repr_to_fn_type_per_tu(die, result);
+  rdr.associate_die_repr_to_fn_type_per_tu(die, result);
 
   {
     die_function_type_map_type::const_iterator i =
-      ctxt.die_wip_function_types_map(source).
+      rdr.die_wip_function_types_map(source).
       find(dwarf_dieoffset(die));
-    if (i != ctxt.die_wip_function_types_map(source).end())
-      ctxt.die_wip_function_types_map(source).erase(i);
+    if (i != rdr.die_wip_function_types_map(source).end())
+      rdr.die_wip_function_types_map(source).erase(i);
   }
 
-  maybe_canonicalize_type(result, ctxt);
+  maybe_canonicalize_type(result, rdr);
   return result;
 }
 
 /// Build a subrange type from a DW_TAG_subrange_type.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param die the DIE to read from.
 ///
@@ -14763,7 +13946,7 @@ build_function_type(read_context&	ctxt,
 /// @return the newly built instance of @ref
 /// array_type_def::subrange_type, or nil if no type could be built.
 static array_type_def::subrange_sptr
-build_subrange_type(read_context&	ctxt,
+build_subrange_type(reader&	rdr,
 		    const Dwarf_Die*		die,
 		    size_t		where_offset,
 		    bool		associate_type_to_die)
@@ -14786,7 +13969,7 @@ build_subrange_type(read_context&	ctxt,
   bool is_signed = false;
   if (die_die_attribute(die, DW_AT_type, underlying_type_die))
     underlying_type =
-      is_type(build_ir_node_from_die(ctxt,
+      is_type(build_ir_node_from_die(rdr,
 				     &underlying_type_die,
 				     /*called_from_public_decl=*/true,
 				     where_offset));
@@ -14800,7 +13983,7 @@ build_subrange_type(read_context&	ctxt,
 	  is_signed = (ate == DW_ATE_signed || ate == DW_ATE_signed_char);
     }
 
-  translation_unit::language language = ctxt.cur_transl_unit()->get_language();
+  translation_unit::language language = rdr.cur_transl_unit()->get_language();
   array_type_def::subrange_type::bound_value lower_bound =
     get_default_array_lower_bound(language);
   array_type_def::subrange_type::bound_value upper_bound;
@@ -14856,7 +14039,7 @@ build_subrange_type(read_context&	ctxt,
     }
 
   result.reset
-    (new array_type_def::subrange_type(ctxt.env(),
+    (new array_type_def::subrange_type(rdr.env(),
 				       name,
 				       lower_bound,
 				       upper_bound,
@@ -14872,7 +14055,7 @@ build_subrange_type(read_context&	ctxt,
 			     - result->get_lower_bound() + 1)));
 
   if (associate_type_to_die)
-    ctxt.associate_die_to_type(die, result, where_offset);
+    rdr.associate_die_to_type(die, result, where_offset);
 
   return result;
 }
@@ -14881,7 +14064,7 @@ build_subrange_type(read_context&	ctxt,
 ///
 /// This is a sub-routine of build_array_type().
 ///
-/// @param ctxt the context to read from.
+/// @param rdr the context to read from.
 ///
 /// @param die the DIE of tag DW_TAG_array_type which contains
 /// children DIEs that represent the sub-ranges.
@@ -14894,7 +14077,7 @@ build_subrange_type(read_context&	ctxt,
 /// e.g, DW_TAG_partial_unit that can be included in several places in
 /// the DIE tree.
 static void
-build_subranges_from_array_type_die(read_context&			ctxt,
+build_subranges_from_array_type_die(reader&			rdr,
 				    const Dwarf_Die*			die,
 				    array_type_def::subranges_type&	subranges,
 				    size_t				where_offset,
@@ -14916,7 +14099,7 @@ build_subranges_from_array_type_die(read_context&			ctxt,
 		  // the current type graph and associate it to the
 		  // DIE it's been created from.
 		  type_or_decl_base_sptr t =
-		    build_ir_node_from_die(ctxt, &child,
+		    build_ir_node_from_die(rdr, &child,
 					   /*called_from_public_decl=*/true,
 					   where_offset);
 		  s = is_subrange_type(t);
@@ -14925,7 +14108,7 @@ build_subranges_from_array_type_die(read_context&			ctxt,
 		// We are being called to create the type but *NOT*
 		// add it to the current tyupe tree, *NOR* associate
 		// it to the DIE it's been created from.
-		s = build_subrange_type(ctxt, &child,
+		s = build_subrange_type(rdr, &child,
 					where_offset,
 					/*associate_type_to_die=*/false);
 	      if (s)
@@ -14938,7 +14121,7 @@ build_subranges_from_array_type_die(read_context&			ctxt,
 
 /// Build an array type from a DW_TAG_array_type DIE.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param die the DIE to read from.
 ///
@@ -14953,7 +14136,7 @@ build_subranges_from_array_type_die(read_context&			ctxt,
 ///
 /// @return a pointer to the resulting array_type_def.
 static array_type_def_sptr
-build_array_type(read_context&	ctxt,
+build_array_type(reader&	rdr,
 		 Dwarf_Die*	die,
 		 bool		called_from_public_decl,
 		 size_t	where_offset)
@@ -14971,7 +14154,7 @@ build_array_type(read_context&	ctxt,
   Dwarf_Die type_die;
 
   if (die_die_attribute(die, DW_AT_type, type_die))
-    type_decl = is_decl(build_ir_node_from_die(ctxt, &type_die,
+    type_decl = is_decl(build_ir_node_from_die(rdr, &type_die,
 					       called_from_public_decl,
 					       where_offset));
   if (!type_decl)
@@ -14979,7 +14162,7 @@ build_array_type(read_context&	ctxt,
 
   // The call to build_ir_node_from_die() could have triggered the
   // creation of the type for this DIE.  In that case, just return it.
-  if (type_base_sptr t = ctxt.lookup_type_from_die(die))
+  if (type_base_sptr t = rdr.lookup_type_from_die(die))
     {
       result = is_array_type(t);
       ABG_ASSERT(result);
@@ -14991,7 +14174,7 @@ build_array_type(read_context&	ctxt,
 
   array_type_def::subranges_type subranges;
 
-  build_subranges_from_array_type_die(ctxt, die, subranges, where_offset);
+  build_subranges_from_array_type_die(rdr, die, subranges, where_offset);
 
   result.reset(new array_type_def(type, subranges, location()));
 
@@ -15000,7 +14183,7 @@ build_array_type(read_context&	ctxt,
 
 /// Create a typedef_decl from a DW_TAG_typedef DIE.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param die the DIE to read from.
 ///
@@ -15015,7 +14198,7 @@ build_array_type(read_context&	ctxt,
 ///
 /// @return the newly created typedef_decl.
 static typedef_decl_sptr
-build_typedef_type(read_context&	ctxt,
+build_typedef_type(reader&	rdr,
 		   Dwarf_Die*		die,
 		   bool		called_from_public_decl,
 		   size_t		where_offset)
@@ -15031,9 +14214,9 @@ build_typedef_type(read_context&	ctxt,
 
   string name, linkage_name;
   location loc;
-  die_loc_and_name(ctxt, die, loc, name, linkage_name);
+  die_loc_and_name(rdr, die, loc, name, linkage_name);
 
-  if (corpus_sptr corp = ctxt.should_reuse_type_from_corpus_group())
+  if (corpus_sptr corp = rdr.should_reuse_type_from_corpus_group())
     if (loc)
       result = lookup_typedef_type_per_location(loc.expand(), *corp);
 
@@ -15044,11 +14227,11 @@ build_typedef_type(read_context&	ctxt,
       if (!die_die_attribute(die, DW_AT_type, underlying_type_die))
 	// A typedef DIE with no underlying type means a typedef to
 	// void type.
-	utype = ctxt.env()->get_void_type();
+	utype = rdr.env().get_void_type();
 
       if (!utype)
 	utype =
-	  is_type(build_ir_node_from_die(ctxt,
+	  is_type(build_ir_node_from_die(rdr,
 					 &underlying_type_die,
 					 called_from_public_decl,
 					 where_offset));
@@ -15069,20 +14252,20 @@ build_typedef_type(read_context&	ctxt,
 	}
     }
 
-  ctxt.associate_die_to_type(die, result, where_offset);
+  rdr.associate_die_to_type(die, result, where_offset);
 
   return result;
 }
 
 /// Build a @ref var_decl out of a DW_TAG_variable DIE if the variable
 /// denoted by the DIE is not suppressed by a suppression
-/// specification associated to the current read context.
+/// specification associated to the current DWARF reader.
 ///
 /// Note that if a member variable declaration with the same name as
 /// the name of the DIE we are looking at exists, this function returns
 /// that existing variable declaration.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @param die the DIE representing the variable we are looking at.
 ///
@@ -15103,7 +14286,7 @@ build_typedef_type(read_context&	ctxt,
 /// @return a pointer to the newly created var_decl.  If the var_decl
 /// could not be built, this function returns NULL.
 static var_decl_sptr
-build_or_get_var_decl_if_not_suppressed(read_context&	ctxt,
+build_or_get_var_decl_if_not_suppressed(reader&	rdr,
 					scope_decl	*scope,
 					Dwarf_Die	*die,
 					size_t	where_offset,
@@ -15111,7 +14294,7 @@ build_or_get_var_decl_if_not_suppressed(read_context&	ctxt,
 					bool is_required_decl_spec)
 {
   var_decl_sptr var;
-  if (variable_is_suppressed(ctxt, scope, die, is_required_decl_spec))
+  if (variable_is_suppressed(rdr, scope, die, is_required_decl_spec))
     return var;
 
   if (class_decl* class_type = is_class_type(scope))
@@ -15121,13 +14304,13 @@ build_or_get_var_decl_if_not_suppressed(read_context&	ctxt,
 	if ((var = class_type->find_data_member(var_name)))
 	  return var;
     }
-  var = build_var_decl(ctxt, die, where_offset, result);
+  var = build_var_decl(rdr, die, where_offset, result);
   return var;
 }
 
 /// Build a @ref var_decl out of a DW_TAG_variable DIE.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @param die the DIE representing the variable we are looking at.
 ///
@@ -15144,7 +14327,7 @@ build_or_get_var_decl_if_not_suppressed(read_context&	ctxt,
 /// @return a pointer to the newly created var_decl.  If the var_decl
 /// could not be built, this function returns NULL.
 static var_decl_sptr
-build_var_decl(read_context&	ctxt,
+build_var_decl(reader&	rdr,
 	       Dwarf_Die	*die,
 	       size_t		where_offset,
 	       var_decl_sptr	result)
@@ -15163,7 +14346,7 @@ build_var_decl(read_context&	ctxt,
   if (die_die_attribute(die, DW_AT_type, type_die))
     {
       decl_base_sptr ty =
-	is_decl(build_ir_node_from_die(ctxt, &type_die,
+	is_decl(build_ir_node_from_die(rdr, &type_die,
 				       /*called_from_public_decl=*/true,
 				       where_offset));
       if (!ty)
@@ -15177,7 +14360,7 @@ build_var_decl(read_context&	ctxt,
 
   string name, linkage_name;
   location loc;
-  die_loc_and_name(ctxt, die, loc, name, linkage_name);
+  die_loc_and_name(rdr, die, loc, name, linkage_name);
 
   if (!result)
     result.reset(new var_decl(name, type, loc, linkage_name));
@@ -15197,13 +14380,15 @@ build_var_decl(read_context&	ctxt,
     {
       elf_symbol_sptr var_sym;
       Dwarf_Addr      var_addr;
-      if (ctxt.get_variable_address(die, var_addr))
+
+      if (rdr.get_variable_address(die, var_addr))
 	{
-	  ctxt.symtab()->update_main_symbol(var_addr,
-					    result->get_linkage_name().empty()
-					      ? result->get_name()
-					      : result->get_linkage_name());
-	  var_sym = ctxt.variable_symbol_is_exported(var_addr);
+	  rdr.symtab()->
+	    update_main_symbol(var_addr,
+			       result->get_linkage_name().empty()
+			       ? result->get_name()
+			       : result->get_linkage_name());
+	  var_sym = rdr.variable_symbol_is_exported(var_addr);
 	}
 
       if (var_sym)
@@ -15229,7 +14414,7 @@ build_var_decl(read_context&	ctxt,
 /// Note that a non-member function which symbol is not exported is
 /// also suppressed.
 ///
-/// @param ctxt the ELF/DWARF reading content of interest.
+/// @param rdr the ELF/DWARF reading content of interest.
 ///
 /// @param scope of the scope of the function.
 ///
@@ -15239,9 +14424,9 @@ build_var_decl(read_context&	ctxt,
 /// a declaration-only DIE.
 ///
 /// @return true iff @p function_die is suppressed by at least one
-/// suppression specification attached to the @p ctxt.
+/// suppression specification attached to the @p rdr.
 static bool
-function_is_suppressed(const read_context& ctxt,
+function_is_suppressed(const reader& rdr,
 		       const scope_decl* scope,
 		       Dwarf_Die *function_die,
 		       bool is_declaration_only)
@@ -15252,7 +14437,7 @@ function_is_suppressed(const read_context& ctxt,
 
   string fname = die_string_attribute(function_die, DW_AT_name);
   string flinkage_name = die_linkage_name(function_die);
-  if (flinkage_name.empty() && ctxt.die_is_in_c(function_die))
+  if (flinkage_name.empty() && rdr.die_is_in_c(function_die))
     flinkage_name = fname;
   string qualified_name = build_qualified_name(scope, fname);
 
@@ -15263,13 +14448,14 @@ function_is_suppressed(const read_context& ctxt,
   // symbol, by default, it's not suppressed.  Unless we are asked to
   // drop undefined symbols too.
   if (!is_class_type(scope)
-      && (!is_declaration_only || ctxt.drop_undefined_syms()))
+      && (!is_declaration_only || rdr.drop_undefined_syms()))
     {
       Dwarf_Addr fn_addr;
-      if (!ctxt.get_function_address(function_die, fn_addr))
+      if (!rdr.get_function_address(function_die, fn_addr))
 	return true;
 
-      elf_symbol_sptr symbol = ctxt.function_symbol_is_exported(fn_addr);
+      elf_symbol_sptr symbol =
+	rdr.function_symbol_is_exported(fn_addr);
       if (!symbol)
 	return true;
       if (!symbol->is_suppressed())
@@ -15286,14 +14472,13 @@ function_is_suppressed(const read_context& ctxt,
 	    return false;
     }
 
-  return suppr::function_is_suppressed(ctxt, qualified_name,
-				       flinkage_name,
+  return suppr::is_function_suppressed(rdr, qualified_name, flinkage_name,
 				       /*require_drop_property=*/true);
 }
 
 /// Build a @ref function_decl out of a DW_TAG_subprogram DIE if the
 /// function denoted by the DIE is not suppressed by a suppression
-/// specification associated to the current read context.
+/// specification associated to the current DWARF reader.
 ///
 /// Note that if a member function declaration with the same signature
 /// (pretty representation) as one of the DIE we are looking at
@@ -15309,7 +14494,7 @@ function_is_suppressed(const read_context& ctxt,
 /// accordingly.  This is done to support "updating" a function_decl
 /// IR with properties scathered across several DIEs.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @param scope the scope of the function we are looking at.
 ///
@@ -15332,7 +14517,7 @@ function_is_suppressed(const read_context& ctxt,
 /// @return a pointer to the newly created var_decl.  If the var_decl
 /// could not be built, this function returns NULL.
 static function_decl_sptr
-build_or_get_fn_decl_if_not_suppressed(read_context&	  ctxt,
+build_or_get_fn_decl_if_not_suppressed(reader&	  rdr,
 				       scope_decl	  *scope,
 				       Dwarf_Die	  *fn_die,
 				       size_t		  where_offset,
@@ -15340,7 +14525,7 @@ build_or_get_fn_decl_if_not_suppressed(read_context&	  ctxt,
 				       function_decl_sptr result)
 {
   function_decl_sptr fn;
-  if (function_is_suppressed(ctxt, scope, fn_die, is_declaration_only))
+  if (function_is_suppressed(rdr, scope, fn_die, is_declaration_only))
     return fn;
 
   string name = die_name(fn_die);
@@ -15364,11 +14549,11 @@ build_or_get_fn_decl_if_not_suppressed(read_context&	  ctxt,
   // symbols.  So re-using C++ destructors like that can lead to us
   // missing some destructors.
   if (!result && (!(is_dtor && is_virtual)))
-    if ((fn = is_function_decl(ctxt.lookup_artifact_from_die(fn_die))))
+    if ((fn = is_function_decl(rdr.lookup_artifact_from_die(fn_die))))
       {
-	fn = maybe_finish_function_decl_reading(ctxt, fn_die, where_offset, fn);
-	ctxt.associate_die_to_decl(fn_die, fn, /*do_associate_by_repr=*/true);
-	ctxt.associate_die_to_type(fn_die, fn->get_type(), where_offset);
+	fn = maybe_finish_function_decl_reading(rdr, fn_die, where_offset, fn);
+	rdr.associate_die_to_decl(fn_die, fn, /*do_associate_by_repr=*/true);
+	rdr.associate_die_to_type(fn_die, fn->get_type(), where_offset);
 	return fn;
       }
 
@@ -15387,7 +14572,7 @@ build_or_get_fn_decl_if_not_suppressed(read_context&	  ctxt,
     // any associated symbol will be dropped on the floor by
     // potential_member_fn_should_be_dropped.  So let's build or a new
     // function IR or complete the existing partial IR.
-    fn = build_function_decl(ctxt, fn_die, where_offset, result);
+    fn = build_function_decl(rdr, fn_die, where_offset, result);
 
   return fn;
 }
@@ -15396,7 +14581,7 @@ build_or_get_fn_decl_if_not_suppressed(read_context&	  ctxt,
 /// suppressed by any of the suppression specifications associated to
 /// a given context of ELF/DWARF reading.
 ///
-/// @param ctxt the ELF/DWARF reading content of interest.
+/// @param rdr the ELF/DWARF reading content of interest.
 ///
 /// @param scope of the scope of the variable.
 ///
@@ -15407,9 +14592,9 @@ build_or_get_fn_decl_if_not_suppressed(read_context&	  ctxt,
 /// specification for a concrete variable being built.
 ///
 /// @return true iff @p variable_die is suppressed by at least one
-/// suppression specification attached to the @p ctxt.
+/// suppression specification attached to the @p rdr.
 static bool
-variable_is_suppressed(const read_context& ctxt,
+variable_is_suppressed(const reader& rdr,
 		       const scope_decl* scope,
 		       Dwarf_Die *variable_die,
 		       bool is_required_decl_spec)
@@ -15421,7 +14606,7 @@ variable_is_suppressed(const read_context& ctxt,
 
   string name = die_string_attribute(variable_die, DW_AT_name);
   string linkage_name = die_linkage_name(variable_die);
-  if (linkage_name.empty() && ctxt.die_is_in_c(variable_die))
+  if (linkage_name.empty() && rdr.die_is_in_c(variable_die))
     linkage_name = name;
   string qualified_name = build_qualified_name(scope, name);
 
@@ -15433,10 +14618,11 @@ variable_is_suppressed(const read_context& ctxt,
   if (!is_class_type(scope) && !is_required_decl_spec)
     {
       Dwarf_Addr var_addr = 0;
-      if (!ctxt.get_variable_address(variable_die, var_addr))
+      if (!rdr.get_variable_address(variable_die, var_addr))
 	return true;
 
-      elf_symbol_sptr symbol = ctxt.variable_symbol_is_exported(var_addr);
+      elf_symbol_sptr symbol =
+	rdr.variable_symbol_is_exported(var_addr);
       if (!symbol)
 	return true;
       if (!symbol->is_suppressed())
@@ -15453,16 +14639,17 @@ variable_is_suppressed(const read_context& ctxt,
 	    return false;
     }
 
-  return suppr::variable_is_suppressed(ctxt, qualified_name,
+  return suppr::is_variable_suppressed(rdr,
+				       qualified_name,
 				       linkage_name,
 				       /*require_drop_property=*/true);
 }
 
 /// Test if a type (designated by a given DIE) in a given scope is
 /// suppressed by the suppression specifications that are associated
-/// to a given read context.
+/// to a given DWARF reader.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param scope of the scope of the type DIE to consider.
 ///
@@ -15475,9 +14662,9 @@ variable_is_suppressed(const read_context& ctxt,
 ///
 /// @return true iff the type designated by the DIE @p type_die, in
 /// the scope @p scope is suppressed by at the suppression
-/// specifications associated to the current read context.
+/// specifications associated to the current DWARF reader.
 static bool
-type_is_suppressed(const read_context& ctxt,
+type_is_suppressed(const reader& rdr,
 		   const scope_decl* scope,
 		   Dwarf_Die *type_die,
 		   bool &type_is_private)
@@ -15491,10 +14678,11 @@ type_is_suppressed(const read_context& ctxt,
 
   string type_name, linkage_name;
   location type_location;
-  die_loc_and_name(ctxt, type_die, type_location, type_name, linkage_name);
+  die_loc_and_name(rdr, type_die, type_location, type_name, linkage_name);
   string qualified_name = build_qualified_name(scope, type_name);
 
-  return suppr::type_is_suppressed(ctxt, qualified_name,
+  return suppr::is_type_suppressed(rdr,
+				   qualified_name,
 				   type_location,
 				   type_is_private,
 				   /*require_drop_property=*/true);
@@ -15502,9 +14690,9 @@ type_is_suppressed(const read_context& ctxt,
 
 /// Test if a type (designated by a given DIE) in a given scope is
 /// suppressed by the suppression specifications that are associated
-/// to a given read context.
+/// to a given DWARF reader.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the DWARF reader to consider.
 ///
 /// @param scope of the scope of the type DIE to consider.
 ///
@@ -15512,14 +14700,14 @@ type_is_suppressed(const read_context& ctxt,
 ///
 /// @return true iff the type designated by the DIE @p type_die, in
 /// the scope @p scope is suppressed by at the suppression
-/// specifications associated to the current read context.
+/// specifications associated to the current DWARF reader.
 static bool
-type_is_suppressed(const read_context& ctxt,
+type_is_suppressed(const reader& rdr,
 		   const scope_decl* scope,
 		   Dwarf_Die *type_die)
 {
   bool type_is_private = false;
-  return type_is_suppressed(ctxt, scope, type_die, type_is_private);
+  return type_is_suppressed(rdr, scope, type_die, type_is_private);
 }
 
 /// Get the opaque version of a type that was suppressed because it's
@@ -15529,7 +14717,7 @@ type_is_suppressed(const read_context& ctxt,
 /// version of the type (class, union or enum type) denoted by @p
 /// type_die.
 ///
-/// @param ctxt the read context in use.
+/// @param rdr the DWARF reader in use.
 ///
 /// @param scope the scope of the type die we are looking at.
 ///
@@ -15543,7 +14731,7 @@ type_is_suppressed(const read_context& ctxt,
 /// @return the opaque version of the type denoted by @p type_die or
 /// nil if no opaque version was found.
 static type_or_decl_base_sptr
-get_opaque_version_of_type(read_context	&ctxt,
+get_opaque_version_of_type(reader	&rdr,
 			   scope_decl		*scope,
 			   Dwarf_Die		*type_die,
 			   size_t		where_offset)
@@ -15562,7 +14750,7 @@ get_opaque_version_of_type(read_context	&ctxt,
 
   string type_name, linkage_name;
   location type_location;
-  die_loc_and_name(ctxt, type_die, type_location, type_name, linkage_name);
+  die_loc_and_name(rdr, type_die, type_location, type_name, linkage_name);
   if (!type_location)
     return result;
 
@@ -15576,8 +14764,8 @@ get_opaque_version_of_type(read_context	&ctxt,
   if (tag == DW_TAG_structure_type || tag == DW_TAG_class_type)
     {
       string_classes_map::const_iterator i =
-	ctxt.declaration_only_classes().find(qualified_name);
-      if (i != ctxt.declaration_only_classes().end())
+	rdr.declaration_only_classes().find(qualified_name);
+      if (i != rdr.declaration_only_classes().end())
 	result = i->second.back();
 
       if (!result)
@@ -15587,7 +14775,7 @@ get_opaque_version_of_type(read_context	&ctxt,
 	  // opaque type.  So let's build one.
 	  //
 	  // TODO: we need to be able to do this for unions too!
-	  class_decl_sptr klass(new class_decl(ctxt.env(), type_name,
+	  class_decl_sptr klass(new class_decl(rdr.env(), type_name,
 					       /*alignment=*/0, /*size=*/0,
 					       tag == DW_TAG_structure_type,
 					       type_location,
@@ -15595,8 +14783,8 @@ get_opaque_version_of_type(read_context	&ctxt,
 	  klass->set_is_declaration_only(true);
 	  klass->set_is_artificial(die_is_artificial(type_die));
 	  add_decl_to_scope(klass, scope);
-	  ctxt.associate_die_to_type(type_die, klass, where_offset);
-	  ctxt.maybe_schedule_declaration_only_class_for_resolution(klass);
+	  rdr.associate_die_to_type(type_die, klass, where_offset);
+	  rdr.maybe_schedule_declaration_only_class_for_resolution(klass);
 	  result = klass;
 	}
     }
@@ -15604,8 +14792,8 @@ get_opaque_version_of_type(read_context	&ctxt,
   if (tag == DW_TAG_enumeration_type)
     {
       string_enums_map::const_iterator i =
-	ctxt.declaration_only_enums().find(qualified_name);
-      if (i != ctxt.declaration_only_enums().end())
+	rdr.declaration_only_enums().find(qualified_name);
+      if (i != rdr.declaration_only_enums().end())
 	result = i->second.back();
 
       if (!result)
@@ -15614,7 +14802,7 @@ get_opaque_version_of_type(read_context	&ctxt,
 	  if (die_unsigned_constant_attribute(type_die, DW_AT_byte_size, size))
 	    size *= 8;
 	  type_decl_sptr underlying_type =
-	    build_enum_underlying_type(ctxt, type_name, size,
+	    build_enum_underlying_type(rdr, type_name, size,
 				       /*anonymous=*/true);
 	  enum_type_decl::enumerators enumeratorz;
 	  enum_type_decl_sptr enum_type (new enum_type_decl(type_name,
@@ -15639,7 +14827,7 @@ get_opaque_version_of_type(read_context	&ctxt,
 ///
 /// @return the newly created symbol.
 elf_symbol_sptr
-create_default_fn_sym(const string& sym_name, const environment *env)
+create_default_fn_sym(const string& sym_name, const environment& env)
 {
   elf_symbol::version ver;
   elf_symbol_sptr result =
@@ -15658,7 +14846,7 @@ create_default_fn_sym(const string& sym_name, const environment *env)
 
 /// Build a @ref function_decl our of a DW_TAG_subprogram DIE.
 ///
-/// @param ctxt the read context to use
+/// @param rdr the DWARF reader to use
 ///
 /// @param die the DW_TAG_subprogram DIE to read from.
 ///
@@ -15670,7 +14858,7 @@ create_default_fn_sym(const string& sym_name, const environment *env)
 /// @param called_for_public_decl this is set to true if the function
 /// was called for a public (function) decl.
 static function_decl_sptr
-build_function_decl(read_context&	ctxt,
+build_function_decl(reader&	rdr,
 		    Dwarf_Die*		die,
 		    size_t		where_offset,
 		    function_decl_sptr	fn)
@@ -15683,16 +14871,16 @@ build_function_decl(read_context&	ctxt,
   if (!die_is_public_decl(die))
     return result;
 
-  translation_unit_sptr tu = ctxt.cur_transl_unit();
+  translation_unit_sptr tu = rdr.cur_transl_unit();
   ABG_ASSERT(tu);
 
   string fname, flinkage_name;
   location floc;
-  die_loc_and_name(ctxt, die, floc, fname, flinkage_name);
+  die_loc_and_name(rdr, die, floc, fname, flinkage_name);
 
   size_t is_inline = die_is_declared_inline(die);
   class_or_union_sptr is_method =
-    is_class_or_union_type(get_scope_for_die(ctxt, die, true, where_offset));
+    is_class_or_union_type(get_scope_for_die(rdr, die, true, where_offset));
 
   if (result)
     {
@@ -15713,12 +14901,12 @@ build_function_decl(read_context&	ctxt,
     }
   else
     {
-      function_type_sptr fn_type(build_function_type(ctxt, die, is_method,
+      function_type_sptr fn_type(build_function_type(rdr, die, is_method,
 						     where_offset));
       if (!fn_type)
 	return result;
 
-      maybe_canonicalize_type(fn_type, ctxt);
+      maybe_canonicalize_type(fn_type, rdr);
 
       result.reset(is_method
 		   ? new method_decl(fname, fn_type,
@@ -15735,16 +14923,17 @@ build_function_decl(read_context&	ctxt,
     {
       elf_symbol_sptr fn_sym;
       Dwarf_Addr      fn_addr;
-      if (ctxt.get_function_address(die, fn_addr))
+      if (rdr.get_function_address(die, fn_addr))
 	{
-	  ctxt.symtab()->update_main_symbol(fn_addr,
-					    result->get_linkage_name().empty()
-					      ? result->get_name()
-					      : result->get_linkage_name());
-	  fn_sym = ctxt.function_symbol_is_exported(fn_addr);
+	  rdr.symtab()->
+	    update_main_symbol(fn_addr,
+			       result->get_linkage_name().empty()
+			       ? result->get_name()
+			       : result->get_linkage_name());
+	  fn_sym = rdr.function_symbol_is_exported(fn_addr);
 	}
 
-      if (fn_sym && !ctxt.symbol_already_belongs_to_a_function(fn_sym))
+      if (fn_sym && !rdr.symbol_already_belongs_to_a_function(fn_sym))
 	{
 	  result->set_symbol(fn_sym);
 	  string linkage_name = result->get_linkage_name();
@@ -15754,7 +14943,7 @@ build_function_decl(read_context&	ctxt,
 	}
     }
 
-  ctxt.associate_die_to_type(die, result->get_type(), where_offset);
+  rdr.associate_die_to_type(die, result->get_type(), where_offset);
 
   size_t die_offset = dwarf_dieoffset(die);
 
@@ -15767,250 +14956,10 @@ build_function_decl(read_context&	ctxt,
     // It thus doesn't need any fixup related to elf symbol.  So
     // remove it from the set of virtual member functions with linkage
     // names and no elf symbol that need to be fixed up.
-    ctxt.die_function_decl_with_no_symbol_map().erase(die_offset);
+    rdr.die_function_decl_with_no_symbol_map().erase(die_offset);
   return result;
 }
 
-/// Read all @ref abigail::translation_unit possible from the debug info
-/// accessible through a DWARF Front End Library handle, and stuff
-/// them into a libabigail ABI Corpus.
-///
-/// @param ctxt the read context.
-///
-/// @return a pointer to the resulting corpus, or NULL if the corpus
-/// could not be constructed.
-static corpus_sptr
-read_debug_info_into_corpus(read_context& ctxt)
-{
-  ctxt.clear_per_corpus_data();
-  ctxt.current_corpus(std::make_shared<corpus>(ctxt.env(), ctxt.elf_path()));
-
-  // First set some mundane properties of the corpus gathered from
-  // ELF.
-  ctxt.current_corpus()->set_path(ctxt.elf_path());
-
-  corpus::origin origin = corpus::DWARF_ORIGIN;
-  if (is_linux_kernel(ctxt.elf_handle()))
-    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
-  ctxt.current_corpus()->set_origin(origin);
-
-  if (origin & corpus::LINUX_KERNEL_BINARY_ORIGIN
-      && !ctxt.env()->user_set_analyze_exported_interfaces_only())
-    // So we are looking at the Linux Kernel and the user has not set
-    // any particular option regarding the amount of types to analyse.
-    // In that case, we need to only analyze types that are reachable
-    // from exported interfaces otherwise we get such a massive amount
-    // of type DIEs to look at that things are just too slow down the
-    // road.
-    ctxt.env()->analyze_exported_interfaces_only(true);
-
-  ctxt.current_corpus()->set_soname(ctxt.dt_soname());
-  ctxt.current_corpus()->set_needed(ctxt.dt_needed());
-  ctxt.current_corpus()->set_architecture_name(ctxt.elf_architecture());
-  if (corpus_group_sptr group = ctxt.current_corpus_group())
-    group->add_corpus(ctxt.current_corpus());
-
-  // Set symbols information to the corpus.
-  ctxt.current_corpus()->set_symtab(ctxt.symtab());
-
-  // Get out now if no debug info is found.
-  if (!ctxt.dwarf())
-    return ctxt.current_corpus();
-
-  uint8_t address_size = 0;
-  size_t header_size = 0;
-
-  // Set the set of exported declaration that are defined.
-  ctxt.exported_decls_builder
-    (ctxt.current_corpus()->get_exported_decls_builder().get());
-
-#ifdef WITH_DEBUG_SELF_COMPARISON
-  if (ctxt.env()->self_comparison_debug_is_on())
-    ctxt.env()->set_self_comparison_debug_input(ctxt.current_corpus());
-#endif
-
-  // Walk all the DIEs of the debug info to build a DIE -> parent map
-  // useful for get_die_parent() to work.
-  {
-    tools_utils::timer t;
-    if (ctxt.do_log())
-      {
-	cerr << "building die -> parent maps ...";
-	t.start();
-      }
-
-    ctxt.build_die_parent_maps();
-
-    if (ctxt.do_log())
-      {
-	t.stop();
-	cerr << " DONE@" << ctxt.current_corpus()->get_path()
-	     << ":"
-	     << t
-	     << "\n";
-      }
-  }
-
-  ctxt.env()->canonicalization_is_done(false);
-
-  {
-    tools_utils::timer t;
-    if (ctxt.do_log())
-      {
-	cerr << "building the libabigail internal representation ...";
-	t.start();
-      }
-    // And now walk all the DIEs again to build the libabigail IR.
-    Dwarf_Half dwarf_version = 0;
-    for (Dwarf_Off offset = 0, next_offset = 0;
-	 (dwarf_next_unit(ctxt.dwarf(), offset, &next_offset, &header_size,
-			  &dwarf_version, NULL, &address_size, NULL,
-			  NULL, NULL) == 0);
-	 offset = next_offset)
-      {
-	Dwarf_Off die_offset = offset + header_size;
-	Dwarf_Die unit;
-	if (!dwarf_offdie(ctxt.dwarf(), die_offset, &unit)
-	    || dwarf_tag(&unit) != DW_TAG_compile_unit)
-	  continue;
-
-	ctxt.dwarf_version(dwarf_version);
-
-	address_size *= 8;
-
-	// Build a translation_unit IR node from cu; note that cu must
-	// be a DW_TAG_compile_unit die.
-	translation_unit_sptr ir_node =
-	  build_translation_unit_and_add_to_ir(ctxt, &unit, address_size);
-	ABG_ASSERT(ir_node);
-      }
-    if (ctxt.do_log())
-      {
-	t.stop();
-	cerr << " DONE@" << ctxt.current_corpus()->get_path()
-	     << ":"
-	     << t
-	     << "\n";
-
-	cerr << "Number of aggregate types compared: "
-	     << ctxt.compare_count_ << "\n"
-	     << "Number of canonical types propagated: "
-	     << ctxt.canonical_propagated_count_ << "\n"
-	     << "Number of cancelled propagated canonical types:"
-	     << ctxt.cancelled_propagation_count_ << "\n";
-      }
-  }
-
-  {
-    tools_utils::timer t;
-    if (ctxt.do_log())
-      {
-	cerr << "resolving declaration only classes ...";
-	t.start();
-      }
-    ctxt.resolve_declaration_only_classes();
-    if (ctxt.do_log())
-      {
-	t.stop();
-	cerr << " DONE@" << ctxt.current_corpus()->get_path()
-	     << ":"
-	     << t
-	     <<"\n";
-      }
-  }
-
-  {
-    tools_utils::timer t;
-    if (ctxt.do_log())
-      {
-	cerr << "resolving declaration only enums ...";
-	t.start();
-      }
-    ctxt.resolve_declaration_only_enums();
-    if (ctxt.do_log())
-      {
-	t.stop();
-	cerr << " DONE@" << ctxt.current_corpus()->get_path()
-	     << ":"
-	     << t
-	     <<"\n";
-      }
-  }
-
-  {
-    tools_utils::timer t;
-    if (ctxt.do_log())
-      {
-	cerr << "fixing up functions with linkage name but "
-	     << "no advertised underlying symbols ....";
-	t.start();
-      }
-    ctxt.fixup_functions_with_no_symbols();
-    if (ctxt.do_log())
-      {
-	t.stop();
-	cerr << " DONE@" << ctxt.current_corpus()->get_path()
-	     <<":"
-	     << t
-	     <<"\n";
-      }
-  }
-
-  /// Now, look at the types that needs to be canonicalized after the
-  /// translation has been constructed (which is just now) and
-  /// canonicalize them.
-  ///
-  /// These types need to be constructed at the end of the translation
-  /// unit reading phase because some types are modified by some DIEs
-  /// even after the principal DIE describing the type has been read;
-  /// this happens for clones of virtual destructors (for instance) or
-  /// even for some static data members.  We need to do that for types
-  /// are in the alternate debug info section and for types that in
-  /// the main debug info section.
-  {
-    tools_utils::timer t;
-    if (ctxt.do_log())
-      {
-	cerr << "perform late type canonicalizing ...\n";
-	t.start();
-      }
-
-    ctxt.perform_late_type_canonicalizing();
-    if (ctxt.do_log())
-      {
-	t.stop();
-	cerr << "late type canonicalizing DONE@"
-	     << ctxt.current_corpus()->get_path()
-	     << ":"
-	     << t
-	     << "\n";
-      }
-  }
-
-  ctxt.env()->canonicalization_is_done(true);
-
-  {
-    tools_utils::timer t;
-    if (ctxt.do_log())
-      {
-	cerr << "sort functions and variables ...";
-	t.start();
-      }
-    ctxt.current_corpus()->sort_functions();
-    ctxt.current_corpus()->sort_variables();
-    if (ctxt.do_log())
-      {
-	t.stop();
-	cerr << " DONE@" << ctxt.current_corpus()->get_path()
-	     << ":"
-	     << t
-	     <<" \n";
-      }
-  }
-
-  return ctxt.current_corpus();
-}
-
 /// Canonicalize a type if it's suitable for early canonicalizing, or,
 /// if it's not, schedule it for late canonicalization, after the
 /// debug info of the current translation unit has been fully read.
@@ -16024,10 +14973,10 @@ read_debug_info_into_corpus(read_context& ctxt)
 ///
 /// @param t the type DIE to consider for canonicalization.
 ///
-/// @param ctxt the @ref read_context to use.
+/// @param rdr the @ref reader to use.
 static void
 maybe_canonicalize_type(const type_base_sptr& t,
-			read_context&	ctxt)
+			reader&	rdr)
 {
   if (!t)
     return;
@@ -16049,9 +14998,9 @@ maybe_canonicalize_type(const type_base_sptr& t,
     // side.  We also delay canonicalization for array and qualified
     // types because they can be edited (in particular by
     // maybe_strip_qualification) after they are initially built.
-    ctxt.schedule_type_for_late_canonicalization(t);
+    rdr.schedule_type_for_late_canonicalization(t);
   else if (type_has_non_canonicalized_subtype(t))
-    ctxt.schedule_type_for_late_canonicalization(t);
+    rdr.schedule_type_for_late_canonicalization(t);
   else
     canonicalize(t);
 }
@@ -16121,10 +15070,10 @@ potential_member_fn_should_be_dropped(const function_decl_sptr& fn,
 }
 
 /// Build an IR node from a given DIE and add the node to the current
-/// IR being build and held in the read_context.  Doing that is called
+/// IR being build and held in the DWARF reader.  Doing that is called
 /// "emitting an IR node for the DIE".
 ///
-/// @param ctxt the read context.
+/// @param rdr the DWARF reader.
 ///
 /// @param die the DIE to consider.
 ///
@@ -16153,7 +15102,7 @@ potential_member_fn_should_be_dropped(const function_decl_sptr& fn,
 ///
 /// @return the resulting IR node.
 static type_or_decl_base_sptr
-build_ir_node_from_die(read_context&	ctxt,
+build_ir_node_from_die(reader&	rdr,
 		       Dwarf_Die*	die,
 		       scope_decl*	scope,
 		       bool		called_from_public_decl,
@@ -16170,7 +15119,7 @@ build_ir_node_from_die(read_context&	ctxt,
 
   if (!called_from_public_decl)
     {
-      if (ctxt.load_all_types() && die_is_type(die))
+      if (rdr.load_all_types() && die_is_type(die))
 	/* We were instructed to load debug info for all types,
 	   included those that are not reachable from a public
 	   declaration.  So load the debug info for this type.  */;
@@ -16181,12 +15130,12 @@ build_ir_node_from_die(read_context&	ctxt,
 	return result;
     }
 
-  const die_source source_of_die = ctxt.get_die_source(die);
+  const die_source source_of_die = rdr.get_die_source(die);
 
-  if ((result = ctxt.lookup_decl_from_die_offset(dwarf_dieoffset(die),
+  if ((result = rdr.lookup_decl_from_die_offset(dwarf_dieoffset(die),
 						 source_of_die)))
     {
-      if (ctxt.load_all_types())
+      if (rdr.load_all_types())
 	if (called_from_public_decl)
 	  if (type_base_sptr t = is_type(result))
 	    if (corpus *abi_corpus = scope->get_corpus())
@@ -16205,10 +15154,10 @@ build_ir_node_from_die(read_context&	ctxt,
     {
       // Type DIEs we support.
     case DW_TAG_base_type:
-      if (type_decl_sptr t = build_type_decl(ctxt, die, where_offset))
+      if (type_decl_sptr t = build_type_decl(rdr, die, where_offset))
 	{
 	  result =
-	    add_decl_to_scope(t, ctxt.cur_transl_unit()->get_global_scope());
+	    add_decl_to_scope(t, rdr.cur_transl_unit()->get_global_scope());
 	  canonicalize(t);
 	}
       break;
@@ -16219,7 +15168,7 @@ build_ir_node_from_die(read_context&	ctxt,
 	t = is_typedef(scope->find_member_type(die_name(die)));
 
 	if (!t)
-	  t = build_typedef_type(ctxt, die,
+	  t = build_typedef_type(rdr, die,
 				 called_from_public_decl,
 				 where_offset);
 
@@ -16227,7 +15176,7 @@ build_ir_node_from_die(read_context&	ctxt,
 	if (result)
 	  {
 	    maybe_set_member_type_access_specifier(is_decl(result), die);
-	    maybe_canonicalize_type(t, ctxt);
+	    maybe_canonicalize_type(t, rdr);
 	  }
       }
       break;
@@ -16235,15 +15184,15 @@ build_ir_node_from_die(read_context&	ctxt,
     case DW_TAG_pointer_type:
       {
 	pointer_type_def_sptr p =
-	  build_pointer_type_def(ctxt, die,
+	  build_pointer_type_def(rdr, die,
 				 called_from_public_decl,
 				 where_offset);
 	if (p)
 	  {
 	    result =
-	      add_decl_to_scope(p, ctxt.cur_transl_unit()->get_global_scope());
+	      add_decl_to_scope(p, rdr.cur_transl_unit()->get_global_scope());
 	    ABG_ASSERT(result->get_translation_unit());
-	    maybe_canonicalize_type(p, ctxt);
+	    maybe_canonicalize_type(p, rdr);
 	  }
       }
       break;
@@ -16252,16 +15201,16 @@ build_ir_node_from_die(read_context&	ctxt,
     case DW_TAG_rvalue_reference_type:
       {
 	reference_type_def_sptr r =
-	  build_reference_type(ctxt, die,
+	  build_reference_type(rdr, die,
 			       called_from_public_decl,
 			       where_offset);
 	if (r)
 	  {
 	    result =
-	      add_decl_to_scope(r, ctxt.cur_transl_unit()->get_global_scope());
+	      add_decl_to_scope(r, rdr.cur_transl_unit()->get_global_scope());
 
-	    ctxt.associate_die_to_type(die, r, where_offset);
-	    maybe_canonicalize_type(r, ctxt);
+	    rdr.associate_die_to_type(die, r, where_offset);
+	    maybe_canonicalize_type(r, rdr);
 	  }
       }
       break;
@@ -16271,7 +15220,7 @@ build_ir_node_from_die(read_context&	ctxt,
     case DW_TAG_restrict_type:
       {
 	type_base_sptr q =
-	  build_qualified_type(ctxt, die,
+	  build_qualified_type(rdr, die,
 			       called_from_public_decl,
 			       where_offset);
 	if (q)
@@ -16279,7 +15228,7 @@ build_ir_node_from_die(read_context&	ctxt,
 	    // Strip some potentially redundant type qualifiers from
 	    // the qualified type we just built.
 	    decl_base_sptr d = maybe_strip_qualification(is_qualified_type(q),
-							 ctxt);
+							 rdr);
 	    if (!d)
 	      d = get_type_declaration(q);
 	    ABG_ASSERT(d);
@@ -16287,10 +15236,10 @@ build_ir_node_from_die(read_context&	ctxt,
 	    // Associate the die to type ty again because 'ty'might be
 	    // different from 'q', because 'ty' is 'q' possibly
 	    // stripped from some redundant type qualifier.
-	    ctxt.associate_die_to_type(die, ty, where_offset);
+	    rdr.associate_die_to_type(die, ty, where_offset);
 	    result =
-	      add_decl_to_scope(d, ctxt.cur_transl_unit()->get_global_scope());
-	    maybe_canonicalize_type(is_type(result), ctxt);
+	      add_decl_to_scope(d, rdr.cur_transl_unit()->get_global_scope());
+	    maybe_canonicalize_type(is_type(result), rdr);
 	  }
       }
       break;
@@ -16299,7 +15248,7 @@ build_ir_node_from_die(read_context&	ctxt,
       {
 	bool type_is_private = false;
 	bool type_suppressed =
-	  type_is_suppressed(ctxt, scope, die, type_is_private);
+	  type_is_suppressed(rdr, scope, die, type_is_private);
 	if (type_suppressed && type_is_private)
 	  {
 	    // The type is suppressed because it's private.  If other
@@ -16308,19 +15257,19 @@ build_ir_node_from_die(read_context&	ctxt,
 	    // non-suppressed instances are opaque versions of the
 	    // suppressed private type.  Lets return one of these opaque
 	    // types then.
-	    result = get_opaque_version_of_type(ctxt, scope, die, where_offset);
-	    maybe_canonicalize_type(is_type(result), ctxt);
+	    result = get_opaque_version_of_type(rdr, scope, die, where_offset);
+	    maybe_canonicalize_type(is_type(result), rdr);
 	  }
 	else if (!type_suppressed)
 	  {
-	    enum_type_decl_sptr e = build_enum_type(ctxt, die, scope,
+	    enum_type_decl_sptr e = build_enum_type(rdr, die, scope,
 						    where_offset,
 						    is_declaration_only);
 	    result = add_decl_to_scope(e, scope);
 	    if (result)
 	      {
 		maybe_set_member_type_access_specifier(is_decl(result), die);
-		maybe_canonicalize_type(is_type(result), ctxt);
+		maybe_canonicalize_type(is_type(result), rdr);
 	      }
 	  }
       }
@@ -16331,7 +15280,7 @@ build_ir_node_from_die(read_context&	ctxt,
       {
 	bool type_is_private = false;
 	bool type_suppressed=
-	  type_is_suppressed(ctxt, scope, die, type_is_private);
+	  type_is_suppressed(rdr, scope, die, type_is_private);
 
 	if (type_suppressed && type_is_private)
 	  {
@@ -16341,8 +15290,8 @@ build_ir_node_from_die(read_context&	ctxt,
 	    // non-suppressed instances are opaque versions of the
 	    // suppressed private type.  Lets return one of these opaque
 	    // types then.
-	    result = get_opaque_version_of_type(ctxt, scope, die, where_offset);
-	    maybe_canonicalize_type(is_type(result), ctxt);
+	    result = get_opaque_version_of_type(rdr, scope, die, where_offset);
+	    maybe_canonicalize_type(is_type(result), rdr);
 	  }
 	else if (!type_suppressed)
 	  {
@@ -16352,12 +15301,12 @@ build_ir_node_from_die(read_context&	ctxt,
 	    if (die_die_attribute(die, DW_AT_specification, spec_die))
 	      {
 		scope_decl_sptr skope =
-		  get_scope_for_die(ctxt, &spec_die,
+		  get_scope_for_die(rdr, &spec_die,
 				    called_from_public_decl,
 				    where_offset);
 		ABG_ASSERT(skope);
 		decl_base_sptr cl =
-		  is_decl(build_ir_node_from_die(ctxt, &spec_die,
+		  is_decl(build_ir_node_from_die(rdr, &spec_die,
 						 skope.get(),
 						 called_from_public_decl,
 						 where_offset,
@@ -16368,7 +15317,7 @@ build_ir_node_from_die(read_context&	ctxt,
 		ABG_ASSERT(klass);
 
 		klass =
-		  add_or_update_class_type(ctxt, die,
+		  add_or_update_class_type(rdr, die,
 					   skope.get(),
 					   tag == DW_TAG_structure_type,
 					   klass,
@@ -16378,7 +15327,7 @@ build_ir_node_from_die(read_context&	ctxt,
 	      }
 	    else
 	      klass =
-		add_or_update_class_type(ctxt, die, scope,
+		add_or_update_class_type(rdr, die, scope,
 					 tag == DW_TAG_structure_type,
 					 class_decl_sptr(),
 					 called_from_public_decl,
@@ -16388,16 +15337,16 @@ build_ir_node_from_die(read_context&	ctxt,
 	    if (klass)
 	      {
 		maybe_set_member_type_access_specifier(klass, die);
-		maybe_canonicalize_type(klass, ctxt);
+		maybe_canonicalize_type(klass, rdr);
 	      }
 	  }
       }
       break;
     case DW_TAG_union_type:
-      if (!type_is_suppressed(ctxt, scope, die))
+      if (!type_is_suppressed(rdr, scope, die))
 	{
 	  union_decl_sptr union_type =
-	    add_or_update_union_type(ctxt, die, scope,
+	    add_or_update_union_type(rdr, die, scope,
 				     union_decl_sptr(),
 				     called_from_public_decl,
 				     where_offset,
@@ -16405,7 +15354,7 @@ build_ir_node_from_die(read_context&	ctxt,
 	  if (union_type)
 	    {
 	      maybe_set_member_type_access_specifier(union_type, die);
-	      maybe_canonicalize_type(union_type, ctxt);
+	      maybe_canonicalize_type(union_type, rdr);
 	    }
 	  result = union_type;
 	}
@@ -16414,29 +15363,29 @@ build_ir_node_from_die(read_context&	ctxt,
       break;
     case DW_TAG_subroutine_type:
       {
-	function_type_sptr f = build_function_type(ctxt, die,
+	function_type_sptr f = build_function_type(rdr, die,
 						   class_decl_sptr(),
 						   where_offset);
 	if (f)
 	  {
 	    result = f;
 	    result->set_is_artificial(false);
-	    maybe_canonicalize_type(f, ctxt);
+	    maybe_canonicalize_type(f, rdr);
 	  }
       }
       break;
     case DW_TAG_array_type:
       {
-	array_type_def_sptr a = build_array_type(ctxt,
+	array_type_def_sptr a = build_array_type(rdr,
 						 die,
 						 called_from_public_decl,
 						 where_offset);
 	if (a)
 	  {
 	    result =
-	      add_decl_to_scope(a, ctxt.cur_transl_unit()->get_global_scope());
-	    ctxt.associate_die_to_type(die, a, where_offset);
-	    maybe_canonicalize_type(a, ctxt);
+	      add_decl_to_scope(a, rdr.cur_transl_unit()->get_global_scope());
+	    rdr.associate_die_to_type(die, a, where_offset);
+	    maybe_canonicalize_type(a, rdr);
 	  }
 	break;
       }
@@ -16446,13 +15395,13 @@ build_ir_node_from_die(read_context&	ctxt,
 	// form" defined in the global namespace of the current
 	// translation unit, like what is found in Ada.
 	array_type_def::subrange_sptr s =
-	  build_subrange_type(ctxt, die, where_offset);
+	  build_subrange_type(rdr, die, where_offset);
 	if (s)
 	  {
 	    result =
-	      add_decl_to_scope(s, ctxt.cur_transl_unit()->get_global_scope());
-	    ctxt.associate_die_to_type(die, s, where_offset);
-	    maybe_canonicalize_type(s, ctxt);
+	      add_decl_to_scope(s, rdr.cur_transl_unit()->get_global_scope());
+	    rdr.associate_die_to_type(die, s, where_offset);
+	    maybe_canonicalize_type(s, rdr);
 	  }
       }
       break;
@@ -16480,7 +15429,7 @@ build_ir_node_from_die(read_context&	ctxt,
 
     case DW_TAG_namespace:
     case DW_TAG_module:
-      result = build_namespace_decl_and_add_to_ir(ctxt, die, where_offset);
+      result = build_namespace_decl_and_add_to_ir(rdr, die, where_offset);
       break;
 
     case DW_TAG_variable:
@@ -16490,21 +15439,21 @@ build_ir_node_from_die(read_context&	ctxt,
 	bool var_is_cloned = false;
 
 	if (tag == DW_TAG_member)
-	  ABG_ASSERT(!is_c_language(ctxt.cur_transl_unit()->get_language()));
+	  ABG_ASSERT(!is_c_language(rdr.cur_transl_unit()->get_language()));
 
 	if (die_die_attribute(die, DW_AT_specification, spec_die, false)
 	    || (var_is_cloned = die_die_attribute(die, DW_AT_abstract_origin,
 						  spec_die, false)))
 	  {
 	    scope_decl_sptr spec_scope =
-	      get_scope_for_die(ctxt, &spec_die,
+	      get_scope_for_die(rdr, &spec_die,
 				/*called_from_public_decl=*/
-				die_is_effectively_public_decl(ctxt, die),
+				die_is_effectively_public_decl(rdr, die),
 				where_offset);
 	    if (spec_scope)
 	      {
 		decl_base_sptr d =
-		  is_decl(build_ir_node_from_die(ctxt, &spec_die,
+		  is_decl(build_ir_node_from_die(rdr, &spec_die,
 						 spec_scope.get(),
 						 called_from_public_decl,
 						 where_offset,
@@ -16516,26 +15465,26 @@ build_ir_node_from_die(read_context&	ctxt,
 		      dynamic_pointer_cast<var_decl>(d);
 		    if (var_is_cloned)
 		      m = m->clone();
-		    m = build_var_decl(ctxt, die, where_offset, m);
+		    m = build_var_decl(rdr, die, where_offset, m);
 		    if (is_data_member(m))
 		      {
 			set_member_is_static(m, true);
-			ctxt.associate_die_to_decl(die, m, where_offset,
+			rdr.associate_die_to_decl(die, m, where_offset,
 						   /*associate_by_repr=*/false);
 		      }
 		    else
 		      {
 			ABG_ASSERT(has_scope(m));
-			ctxt.var_decls_to_re_add_to_tree().push_back(m);
+			rdr.var_decls_to_re_add_to_tree().push_back(m);
 		      }
 		    ABG_ASSERT(m->get_scope());
-		    ctxt.maybe_add_var_to_exported_decls(m.get());
+		    rdr.maybe_add_var_to_exported_decls(m.get());
 		    result = m;
 		  }
 	      }
 	  }
 	else if (var_decl_sptr v =
-		 build_or_get_var_decl_if_not_suppressed(ctxt, scope, die,
+		 build_or_get_var_decl_if_not_suppressed(rdr, scope, die,
 							 where_offset,
 							 /*result=*/var_decl_sptr(),
 							 is_required_decl_spec))
@@ -16545,8 +15494,8 @@ build_ir_node_from_die(read_context&	ctxt,
 	    v = dynamic_pointer_cast<var_decl>(result);
 	    ABG_ASSERT(v);
 	    ABG_ASSERT(v->get_scope());
-	    ctxt.var_decls_to_re_add_to_tree().push_back(v);
-	    ctxt.maybe_add_var_to_exported_decls(v.get());
+	    rdr.var_decls_to_re_add_to_tree().push_back(v);
+	    rdr.maybe_add_var_to_exported_decls(v.get());
 	  }
       }
       break;
@@ -16580,7 +15529,7 @@ build_ir_node_from_die(read_context&	ctxt,
 	    string linkage_name = die_linkage_name(die);
 	    string spec_linkage_name = die_linkage_name(interface_die);
 
-	    interface_scope = get_scope_for_die(ctxt, interface_die,
+	    interface_scope = get_scope_for_die(rdr, interface_die,
 						called_from_public_decl,
 						where_offset);
 	    if (interface_scope)
@@ -16591,7 +15540,7 @@ build_ir_node_from_die(read_context&	ctxt,
 		  d = c->find_member_function_sptr(linkage_name);
 
 		if (!d)
-		  d = is_decl(build_ir_node_from_die(ctxt,
+		  d = is_decl(build_ir_node_from_die(rdr,
 						     origin_die,
 						     interface_scope.get(),
 						     called_from_public_decl,
@@ -16612,14 +15561,14 @@ build_ir_node_from_die(read_context&	ctxt,
 		  }
 	      }
 	  }
-	ctxt.scope_stack().push(scope);
+	rdr.scope_stack().push(scope);
 
 	scope_decl* logical_scope =
 	  interface_scope
 	  ? interface_scope.get()
 	  : scope;
 
-	result = build_or_get_fn_decl_if_not_suppressed(ctxt, logical_scope,
+	result = build_or_get_fn_decl_if_not_suppressed(rdr, logical_scope,
 							die, where_offset,
 							is_declaration_only,
 							fn);
@@ -16642,18 +15591,18 @@ build_ir_node_from_die(read_context&	ctxt,
 	    class_decl_sptr klass(static_cast<class_decl*>(logical_scope),
 				  sptr_utils::noop_deleter());
 	    ABG_ASSERT(klass);
-	    finish_member_function_reading(die, fn, klass, ctxt);
+	    finish_member_function_reading(die, fn, klass, rdr);
 	  }
 
 	if (fn)
 	  {
-	    ctxt.maybe_add_fn_to_exported_decls(fn.get());
-	    ctxt.associate_die_to_decl(die, fn, where_offset,
+	    rdr.maybe_add_fn_to_exported_decls(fn.get());
+	    rdr.associate_die_to_decl(die, fn, where_offset,
 				       /*associate_by_repr=*/false);
-	    maybe_canonicalize_type(fn->get_type(), ctxt);
+	    maybe_canonicalize_type(fn->get_type(), rdr);
 	  }
 
-	ctxt.scope_stack().pop();
+	rdr.scope_stack().pop();
       }
       break;
 
@@ -16718,11 +15667,11 @@ build_ir_node_from_die(read_context&	ctxt,
     }
 
   if (result && tag != DW_TAG_subroutine_type)
-    ctxt.associate_die_to_decl(die, is_decl(result), where_offset,
+    rdr.associate_die_to_decl(die, is_decl(result), where_offset,
 			       /*associate_by_repr=*/false);
 
   if (result)
-    if (ctxt.load_all_types())
+    if (rdr.load_all_types())
       if (called_from_public_decl)
 	if (type_base_sptr t = is_type(result))
 	  if (corpus *abi_corpus = scope->get_corpus())
@@ -16733,48 +15682,48 @@ build_ir_node_from_die(read_context&	ctxt,
 
 ///  Build the IR node for a void type.
 ///
-///  @param ctxt the read context to use.
+///  @param rdr the DWARF reader to use.
 ///
 ///  @return the void type node.
 static decl_base_sptr
-build_ir_node_for_void_type(read_context& ctxt)
+build_ir_node_for_void_type(reader& rdr)
 {
-  ir::environment* env = ctxt.env();
-  ABG_ASSERT(env);
-  type_base_sptr t = env->get_void_type();
+  const environment& env = rdr.env();
+
+  type_base_sptr t = env.get_void_type();
   decl_base_sptr type_declaration = get_type_declaration(t);
   if (!has_scope(type_declaration))
     add_decl_to_scope(type_declaration,
-		      ctxt.cur_transl_unit()->get_global_scope());
+		      rdr.cur_transl_unit()->get_global_scope());
   canonicalize(t);
   return type_declaration;
 }
 
 /// Build the IR node for a variadic parameter type.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the DWARF reader to use.
 ///
 /// @return the variadic parameter type.
 static decl_base_sptr
-build_ir_node_for_variadic_parameter_type(read_context &ctxt)
+build_ir_node_for_variadic_parameter_type(reader &rdr)
 {
 
-  ir::environment* env = ctxt.env();
-  ABG_ASSERT(env);
-  type_base_sptr t = env->get_variadic_parameter_type();
+  const environment& env = rdr.env();
+
+  type_base_sptr t = env.get_variadic_parameter_type();
   decl_base_sptr type_declaration = get_type_declaration(t);
   if (!has_scope(type_declaration))
     add_decl_to_scope(type_declaration,
-		      ctxt.cur_transl_unit()->get_global_scope());
+		      rdr.cur_transl_unit()->get_global_scope());
   canonicalize(t);
   return type_declaration;
 }
 
 /// Build an IR node from a given DIE and add the node to the current
-/// IR being build and held in the read_context.  Doing that is called
+/// IR being build and held in the DWARF reader.  Doing that is called
 /// "emitting an IR node for the DIE".
 ///
-/// @param ctxt the read context.
+/// @param rdr the DWARF reader.
 ///
 /// @param die the DIE to consider.
 ///
@@ -16793,7 +15742,7 @@ build_ir_node_for_variadic_parameter_type(read_context &ctxt)
 ///
 /// @return the resulting IR node.
 static type_or_decl_base_sptr
-build_ir_node_from_die(read_context&	ctxt,
+build_ir_node_from_die(reader&	rdr,
 		       Dwarf_Die*	die,
 		       bool		called_from_public_decl,
 		       size_t		where_offset)
@@ -16801,10 +15750,10 @@ build_ir_node_from_die(read_context&	ctxt,
   if (!die)
     return decl_base_sptr();
 
-  if (is_c_language(ctxt.cur_transl_unit()->get_language()))
+  if (is_c_language(rdr.cur_transl_unit()->get_language()))
     {
-      const scope_decl_sptr& scop = ctxt.global_scope();
-      return build_ir_node_from_die(ctxt, die, scop.get(),
+      const scope_decl_sptr& scop = rdr.global_scope();
+      return build_ir_node_from_die(rdr, die, scop.get(),
 				    called_from_public_decl,
 				    where_offset,
                                     true);
@@ -16819,17 +15768,17 @@ build_ir_node_from_die(read_context&	ctxt,
   // to it, it'll be dropped on the floor anyway.  Those variable
   // decls are considered as being "effectively public".
   bool consider_as_called_from_public_decl =
-    called_from_public_decl || die_is_effectively_public_decl(ctxt, die);
-  scope_decl_sptr scope = get_scope_for_die(ctxt, die,
+    called_from_public_decl || die_is_effectively_public_decl(rdr, die);
+  scope_decl_sptr scope = get_scope_for_die(rdr, die,
 					    consider_as_called_from_public_decl,
 					    where_offset);
-  return build_ir_node_from_die(ctxt, die, scope.get(),
+  return build_ir_node_from_die(rdr, die, scope.get(),
 				called_from_public_decl,
 				where_offset,
                                 true);
 }
 
-/// Create a dwarf_reader::read_context.
+/// Create a dwarf_reader::reader.
 ///
 /// @param elf_path the path to the elf file the context is to be used for.
 ///
@@ -16839,14 +15788,14 @@ build_ir_node_from_die(read_context&	ctxt,
 /// file.
 ///
 /// @param environment the environment used by the current context.
-/// This environment contains resources needed by the reader and by
+/// This environment contains resources needed by the DWARF 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.
 ///
 /// Please also note that the life time of this environment object
 /// must be greater than the life time of the resulting @ref
-/// read_context the context uses resources that are allocated in the
+/// reader the context uses resources that are allocated in the
 /// environment.
 ///
 /// @param load_all_types if set to false only the types that are
@@ -16858,33 +15807,27 @@ build_ir_node_from_die(read_context&	ctxt,
 /// linux kernel symbol tables when determining if a symbol is
 /// exported or not.
 ///
-/// @return a smart pointer to the resulting dwarf_reader::read_context.
-read_context_sptr
-create_read_context(const std::string&		elf_path,
+/// @return a smart pointer to the resulting dwarf_reader::reader.
+elf_based_reader_sptr
+create_dwarf_reader(const std::string&		elf_path,
 		    const vector<char**>&	debug_info_root_paths,
-		    ir::environment*		environment,
+		    environment&		environment,
 		    bool			load_all_types,
 		    bool			linux_kernel_mode)
 {
-  // Create a DWARF Front End Library handle to be used by functions
-  // of that library.
-  read_context_sptr result(new read_context(elf_path, debug_info_root_paths,
-					    environment, load_all_types,
-					    linux_kernel_mode));
-  return result;
-}
 
-/// Getter for the path to the binary this @ref read_context is for.
-///
-/// @return the path to the binary the @ref read_context is for.
-const string&
-read_context_get_path(const read_context& ctxt)
-{return ctxt.elf_path();}
+  reader_sptr r = reader::create(elf_path,
+				 debug_info_root_paths,
+				 environment,
+				 load_all_types,
+				 linux_kernel_mode);
+  return static_pointer_cast<elf_based_reader>(r);
+}
 
-/// Re-initialize a read_context so that it can re-used to read
+/// Re-initialize a reader so that it can re-used to read
 /// another binary.
 ///
-/// @param ctxt the context to re-initialize.
+/// @param rdr the context to re-initialize.
 ///
 /// @param elf_path the path to the elf file the context is to be used
 /// for.
@@ -16895,14 +15838,14 @@ read_context_get_path(const read_context& ctxt)
 /// file.
 ///
 /// @param environment the environment used by the current context.
-/// This environment contains resources needed by the reader and by
+/// This environment contains resources needed by the DWARF 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.
 ///
 /// Please also note that the life time of this environment object
 /// must be greater than the life time of the resulting @ref
-/// read_context the context uses resources that are allocated in the
+/// reader the context uses resources that are allocated in the
 /// environment.
 ///
 /// @param load_all_types if set to false only the types that are
@@ -16914,137 +15857,17 @@ read_context_get_path(const read_context& ctxt)
 /// linux kernel symbol tables when determining if a symbol is
 /// exported or not.
 ///
-/// @return a smart pointer to the resulting dwarf_reader::read_context.
-void
-reset_read_context(read_context_sptr	&ctxt,
-		   const std::string&	 elf_path,
-		   const vector<char**>& debug_info_root_path,
-		   ir::environment*	 environment,
-		   bool		 read_all_types,
-		   bool		 linux_kernel_mode)
-{
-  if (ctxt)
-    ctxt->initialize(elf_path, debug_info_root_path, environment,
-		     read_all_types, linux_kernel_mode);
-}
-
-/// Add suppressions specifications to the set of suppressions to be
-/// used during the construction of the ABI internal representation
-/// (the ABI corpus) from ELF and DWARF.
-///
-/// During the construction of the ABI corpus, ABI artifacts that
-/// match the a given suppression specification are dropped on the
-/// floor; that is, they are discarded and won't be part of the final
-/// ABI corpus.  This is a way to reduce the amount of data held by
-/// the final ABI corpus.
-///
-/// Note that the suppression specifications provided to this function
-/// are only considered during the construction of the ABI corpus.
-/// For instance, they are not taken into account during e.g
-/// comparisons of two ABI corpora that might happen later.  If you
-/// want to apply suppression specificatins to the comparison (or
-/// reporting) of ABI corpora please refer to the documentation of the
-/// @ref diff_context type to learn how to set suppressions that are
-/// to be used in that context.
-///
-/// @param ctxt the context that is going to be used by functions that
-/// read ELF and DWARF information to construct and ABI corpus.
-///
-/// @param supprs the suppression specifications to be applied during
-/// the construction of the ABI corpus.
-void
-add_read_context_suppressions(read_context& ctxt,
-			      const suppr::suppressions_type& supprs)
-{
-  for (suppr::suppressions_type::const_iterator i = supprs.begin();
-       i != supprs.end();
-       ++i)
-    if ((*i)->get_drops_artifact_from_ir())
-      ctxt.get_suppressions().push_back(*i);
-}
-
-/// Set the @ref corpus_group being created to the current read context.
-///
-/// @param ctxt the read_context to consider.
-///
-/// @param group the @ref corpus_group to set.
+/// @return a smart pointer to the resulting dwarf_reader::reader.
 void
-set_read_context_corpus_group(read_context& ctxt,
-			      corpus_group_sptr& group)
-{
-  ctxt.cur_corpus_group_ = group;
-}
-
-/// Read all @ref abigail::translation_unit possible from the debug info
-/// accessible from an elf file, stuff them into a libabigail ABI
-/// Corpus and return it.
-///
-/// @param ctxt the context to use for reading the elf file.
-///
-/// @param resulting_corp a pointer to the resulting abigail::corpus.
-///
-/// @return the resulting status.
-corpus_sptr
-read_corpus_from_elf(read_context& ctxt, status& status)
-{
-  status = STATUS_UNKNOWN;
-
-  // Load debug info from the elf path.
-  if (!ctxt.load_debug_info())
-    status |= STATUS_DEBUG_INFO_NOT_FOUND;
-
-  {
-    string alt_di_path;
-    if (refers_to_alt_debug_info(ctxt, alt_di_path) && !ctxt.alt_dwarf())
-      status |= STATUS_ALT_DEBUG_INFO_NOT_FOUND;
-  }
-
-  ctxt.load_elf_properties();  // DT_SONAME, DT_NEEDED, architecture
-
-  if (!ctxt.symtab() || !ctxt.symtab()->has_symbols())
-    status |= STATUS_NO_SYMBOLS_FOUND;
-
-  if (// If no elf symbol was found ...
-      status & STATUS_NO_SYMBOLS_FOUND
-      // ... or if debug info was found but not the required alternate
-      // debug info ...
-      || ((status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
-	  && !(status & STATUS_DEBUG_INFO_NOT_FOUND)))
-    // ... then we cannot handle the binary.
-    return corpus_sptr();
-
-  // Read the variable and function descriptions from the debug info
-  // we have, through the dwfl handle.
-  corpus_sptr corp = read_debug_info_into_corpus(ctxt);
-
-  status |= STATUS_OK;
-
-  return corp;
-}
-
-/// Read a corpus and add it to a given @ref corpus_group.
-///
-/// @param ctxt the reading context to consider.
-///
-/// @param group the @ref corpus_group to add the new corpus to.
-///
-/// @param status output parameter. The status of the read.  It is set
-/// by this function upon its completion.
-corpus_sptr
-read_and_add_corpus_to_group_from_elf(read_context& ctxt,
-				      corpus_group& group,
-				      status& status)
+reset_dwarf_reader(elf_based_reader&	rdr,
+		   const std::string&	elf_path,
+		   const vector<char**>&debug_info_root_path,
+		   bool		read_all_types,
+		   bool		linux_kernel_mode)
 {
-  corpus_sptr result;
-  corpus_sptr corp = read_corpus_from_elf(ctxt, status);
-  if (status & STATUS_OK)
-    {
-      if (!corp->get_group())
-	group.add_corpus(corp);
-      result = corp;
-    }
-
-  return result;
+  reader& r = dynamic_cast<reader&>(rdr);
+  r.initialize(elf_path, debug_info_root_path,
+	       read_all_types, linux_kernel_mode);
 }
 
 /// Read all @ref abigail::translation_unit possible from the debug info
@@ -17063,7 +15886,7 @@ read_and_add_corpus_to_group_from_elf(read_context& ctxt,
 /// containing the debug info file.
 ///
 /// @param environment the environment used by the current context.
-/// This environment contains resources needed by the reader and by
+/// This environment contains resources needed by the DWARF 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.  Also, the lifetime of the
@@ -17082,16 +15905,16 @@ read_and_add_corpus_to_group_from_elf(read_context& ctxt,
 corpus_sptr
 read_corpus_from_elf(const std::string& elf_path,
 		     const vector<char**>& debug_info_root_paths,
-		     ir::environment*	environment,
+		     environment&	environment,
 		     bool		load_all_types,
-		     status&		status)
+		     fe_iface::status&	status)
 {
-  read_context_sptr c = create_read_context(elf_path,
-					    debug_info_root_paths,
-					    environment,
-					    load_all_types);
-  read_context& ctxt = *c;
-  return read_corpus_from_elf(ctxt, status);
+  elf_based_reader_sptr rdr =
+    dwarf_reader::reader::create(elf_path, debug_info_root_paths,
+				 environment, load_all_types,
+				 /*linux_kernel_mode=*/false);
+
+  return rdr->read_corpus(status);
 }
 
 /// Look into the symbol tables of a given elf file and see if we find
@@ -17111,7 +15934,7 @@ read_corpus_from_elf(const std::string& elf_path,
 /// @return true iff the symbol was found among the publicly exported
 /// symbols of the ELF file.
 bool
-lookup_symbol_from_elf(const environment*		env,
+lookup_symbol_from_elf(environment&			env,
 		       const string&			elf_path,
 		       const string&			symbol_name,
 		       bool				demangle,
@@ -17156,7 +15979,7 @@ lookup_symbol_from_elf(const environment*		env,
 /// @return true iff a function with symbol name @p symbol_name is
 /// found.
 bool
-lookup_public_function_symbol_from_elf(const environment*		env,
+lookup_public_function_symbol_from_elf(environment&			env,
 				       const string&			path,
 				       const string&			symname,
 				       vector<elf_symbol_sptr>&	syms)
@@ -17183,218 +16006,6 @@ lookup_public_function_symbol_from_elf(const environment*		env,
   return value;
 }
 
-/// Check if the underlying elf file refers to an alternate debug info
-/// file associated to it.
-///
-/// Note that "alternate debug info sections" is a GNU extension as
-/// of DWARF4 and is described at
-/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
-///
-/// @param ctxt the context used to read the elf file.
-///
-/// @param alt_di the path to the alternate debug info file.  This is
-/// set iff the function returns true.
-///
-/// @return true if the ELF file refers to an alternate debug info
-/// file.
-bool
-refers_to_alt_debug_info(const read_context&	ctxt,
-			 string&		alt_di_path)
-{
-  if (!ctxt.alt_debug_info_path().empty())
-    {
-      alt_di_path = ctxt.alt_debug_info_path();
-      return true;
-    }
-  return false;
-}
-
-/// Check if the underlying elf file has an alternate debug info file
-/// associated to it.
-///
-/// Note that "alternate debug info sections" is a GNU extension as
-/// of DWARF4 and is described at
-/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
-///
-/// @param ctxt the read_context to use to handle the underlying elf file.
-///
-/// @param has_alt_di out parameter.  This is set to true upon
-/// succesful completion of the function iff an alternate debug info
-/// file was found, false otherwise.  Note thas this parameter is set
-/// only if the function returns STATUS_OK.
-///
-/// @param alt_debug_info_path if the function returned STATUS_OK and
-/// if @p has been set to true, then this parameter contains the path
-/// to the alternate debug info file found.
-///
-/// return STATUS_OK upon successful completion, false otherwise.
-status
-has_alt_debug_info(read_context&	ctxt,
-		   bool&		has_alt_di,
-		   string&		alt_debug_info_path)
-{
-  // Load debug info from the elf path.
-  if (!ctxt.load_debug_info())
-    return STATUS_DEBUG_INFO_NOT_FOUND;
-
-  if (ctxt.alt_dwarf())
-    {
-      has_alt_di = true;
-      alt_debug_info_path = ctxt.alt_debug_info_path();
-    }
-  else
-    has_alt_di = false;
-
-  return STATUS_OK;
-}
-
-/// Check if a given elf file has an alternate debug info file
-/// associated to it.
-///
-/// Note that "alternate debug info sections" is a GNU extension as
-/// of DWARF4 and is described at
-/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
-///
-/// @param elf_path the path to the elf file to consider.
-///
-/// @param a pointer to the root directory under which the split debug info
-/// file associated to elf_path is to be found.  This has to be NULL
-/// if the debug info file is not in a split file.
-///
-/// @param has_alt_di out parameter.  This is set to true upon
-/// succesful completion of the function iff an alternate debug info
-/// file was found, false otherwise.  Note thas this parameter is set
-/// only if the function returns STATUS_OK.
-///
-/// @param alt_debug_info_path if the function returned STATUS_OK and
-/// if @p has been set to true, then this parameter contains the path
-/// to the alternate debug info file found.
-///
-/// return STATUS_OK upon successful completion, false otherwise.
-status
-has_alt_debug_info(const string&	elf_path,
-		   char**		debug_info_root_path,
-		   bool&		has_alt_di,
-		   string&		alt_debug_info_path)
-{
-  vector<char**> di_roots;
-  di_roots.push_back(debug_info_root_path);
-  read_context_sptr c = create_read_context(elf_path, di_roots, 0);
-  read_context& ctxt = *c;
-
-  // Load debug info from the elf path.
-  if (!ctxt.load_debug_info())
-    return STATUS_DEBUG_INFO_NOT_FOUND;
-
-  if (ctxt.alt_dwarf())
-    {
-      has_alt_di = true;
-      alt_debug_info_path = ctxt.alt_debug_info_path();
-    }
-  else
-    has_alt_di = false;
-
-  return STATUS_OK;
-}
-
-/// Fetch the SONAME ELF property from an ELF binary file.
-///
-/// @param path The path to the elf file to consider.
-///
-/// @param soname out parameter. Set to the SONAME property of the
-/// binary file, if it present in the ELF file.
-///
-/// return false if an error occured while looking for the SONAME
-/// property in the binary, true otherwise.
-bool
-get_soname_of_elf_file(const string& path, string &soname)
-{
-
-  int fd = open(path.c_str(), O_RDONLY);
-  if (fd == -1)
-    return false;
-
-  elf_version (EV_CURRENT);
-  Elf* elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
-
-  GElf_Ehdr ehdr_mem;
-  GElf_Ehdr* ehdr = gelf_getehdr (elf, &ehdr_mem);
-  if (ehdr == NULL)
-    return false;
-
-  for (int i = 0; i < ehdr->e_phnum; ++i)
-    {
-      GElf_Phdr phdr_mem;
-      GElf_Phdr* phdr = gelf_getphdr (elf, i, &phdr_mem);
-
-      if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
-        {
-          Elf_Scn* scn = gelf_offscn (elf, phdr->p_offset);
-          GElf_Shdr shdr_mem;
-          GElf_Shdr* shdr = gelf_getshdr (scn, &shdr_mem);
-          size_t entsize = (shdr != NULL && shdr->sh_entsize != 0
-                            ? shdr->sh_entsize
-                            : gelf_fsize (elf, ELF_T_DYN, 1, EV_CURRENT));
-          int maxcnt = (shdr != NULL
-                        ? shdr->sh_size / entsize : INT_MAX);
-          ABG_ASSERT (shdr == NULL || (shdr->sh_type == SHT_DYNAMIC
-				       || shdr->sh_type == SHT_PROGBITS));
-          Elf_Data* data = elf_getdata (scn, NULL);
-          if (data == NULL)
-            break;
-
-          for (int cnt = 0; cnt < maxcnt; ++cnt)
-            {
-              GElf_Dyn dynmem;
-              GElf_Dyn* dyn = gelf_getdyn (data, cnt, &dynmem);
-              if (dyn == NULL)
-                continue;
-
-              if (dyn->d_tag == DT_NULL)
-                break;
-
-              if (dyn->d_tag != DT_SONAME)
-                continue;
-
-              soname = elf_strptr (elf, shdr->sh_link, dyn->d_un.d_val);
-              break;
-            }
-          break;
-        }
-    }
-
-  elf_end(elf);
-  close(fd);
-
-  return true;
-}
-
-/// Get the type of a given elf type.
-///
-/// @param path the absolute path to the ELF file to analyzed.
-///
-/// @param type the kind of the ELF file designated by @p path.
-///
-/// @param out parameter.  Is set to the type of ELF file of @p path.
-/// This parameter is set iff the function returns true.
-///
-/// @return true iff the file could be opened and analyzed.
-bool
-get_type_of_elf_file(const string& path, elf_type& type)
-{
-  int fd = open(path.c_str(), O_RDONLY);
-  if (fd == -1)
-    return false;
-
-  elf_version (EV_CURRENT);
-  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
-  type = elf_file_type(elf);
-  elf_end(elf);
-  close(fd);
-
-  return true;
-}
-
 }// end namespace dwarf_reader
 
 }// end namespace abigail
diff --git a/src/abg-elf-based-reader.cc b/src/abg-elf-based-reader.cc
new file mode 100644
index 00000000..b8e5eb09
--- /dev/null
+++ b/src/abg-elf-based-reader.cc
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// -*- Mode: C++ -*-
+//
+// Copyright (C) 2022 Red Hat, Inc.
+//
+// Author: Dodji Seketeli
+
+/// @file
+///
+/// This file contains the definitions of the entry points of the
+/// generic interface for ELF-based front-ends.  The generic interface
+/// for ELF-based front-ends is named @ref elf_based_reader.  Examples
+/// of front-ends that implement that interface are @ref
+/// abigail::dwarf_reader::reader and abigail::ctf_raeder::reader.
+
+#include "abg-internal.h"
+
+// <headers defining libabigail's API go under here>
+ABG_BEGIN_EXPORT_DECLARATIONS
+
+#include "abg-elf-based-reader.h"
+
+ABG_END_EXPORT_DECLARATIONS
+// </headers defining libabigail's API>
+namespace abigail
+{
+
+/// The private data of the @ref elf_based_reader type.
+struct elf_based_reader::priv
+{
+
+  void
+  initialize()
+  {
+  }
+
+  priv()
+  {
+    initialize();
+  }
+}; // end struct elf_based_reader::priv
+
+/// Constructor of the @erf elf_based_reader type.
+///
+/// @param elf_path the path the ELF file to read.
+///
+/// @param debug_info_root_paths a vector of paths to look into for
+/// split debug info files.
+///
+/// @param env the environment used by the reader.
+elf_based_reader::elf_based_reader(const std::string& elf_path,
+				   const vector<char**>& debug_info_root_paths,
+				   environment& env)
+  : elf_reader::reader(elf_path, debug_info_root_paths, env),
+    priv_(new priv)
+{
+  priv_->initialize();
+}
+
+/// Destructor of the reader.
+elf_based_reader::~elf_based_reader()
+{delete priv_;}
+
+/// Reset (re-initialize) the resources used by the current reader.
+///
+/// This frees the resources of the current reader and gets it ready
+/// to read data from another ELF file.
+///
+/// @param elf_path the path to the new ELF file to consider.
+///
+/// @param debug_info_root_paths a vector of paths to look into for
+/// split debug info files.
+void
+elf_based_reader::reset(const std::string& elf_path,
+			const vector<char**>& debug_info_root_paths)
+{
+  elf_reader::reader::reset(elf_path, debug_info_root_paths);
+  priv_->initialize();
+}
+
+/// Read an ABI corpus and add it to a given corpus group.
+///
+/// @param group the corpus group to consider.  The new corpus is
+/// added to this group.
+///
+/// @param status output parameter.  This is the status of the
+/// creation of the current ABI corpus.  It's set by this function iff
+/// a non-nil @ref corpus_sptr is returned.
+///
+/// @return the resulting ABI corpus.
+ir::corpus_sptr
+elf_based_reader::read_and_add_corpus_to_group(ir::corpus_group& group,
+					       fe_iface::status& status)
+{
+  ir::corpus_sptr corp = read_corpus(status);
+
+  if (status & fe_iface::STATUS_OK)
+    group.add_corpus(corp);
+  return corp;
+}
+
+} // end namespace abigail
diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc
index cbcf5428..8221ff84 100644
--- a/src/abg-elf-helpers.cc
+++ b/src/abg-elf-helpers.cc
@@ -6,11 +6,13 @@
 /// @file
 ///
 /// This contains the definitions of the ELF utilities for the dwarf reader.
-
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <elfutils/libdwfl.h>
 #include "abg-elf-helpers.h"
-
-#include <elf.h>
-
 #include "abg-tools-utils.h"
 
 namespace abigail
@@ -1333,6 +1335,179 @@ address_is_in_opd_section(Elf* elf_handle, Dwarf_Addr addr)
   return false;
 }
 
+/// Get data tag information of an ELF file by looking up into its
+/// dynamic segment
+///
+/// @param elf the elf handle to use for the query.
+///
+/// @param dt_tag data tag to look for in dynamic segment
+/// @param dt_tag_data vector of found information for a given @p data_tag
+///
+/// @return true iff data tag @p data_tag was found
+bool
+lookup_data_tag_from_dynamic_segment(Elf*                       elf,
+                                     Elf64_Sxword               data_tag,
+                                     vector<string>&            dt_tag_data)
+{
+  size_t num_prog_headers = 0;
+  bool found = false;
+  if (elf_getphdrnum(elf, &num_prog_headers) < 0)
+    return found;
+
+  // Cycle through each program header.
+  for (size_t i = 0; i < num_prog_headers; ++i)
+    {
+      GElf_Phdr phdr_mem;
+      GElf_Phdr *phdr = gelf_getphdr(elf, i, &phdr_mem);
+      if (phdr == NULL || phdr->p_type != PT_DYNAMIC)
+        continue;
+
+      // Poke at the dynamic segment like a section, so that we can
+      // get its section header information; also we'd like to read
+      // the data of the segment by using elf_getdata() but that
+      // function needs a Elf_Scn data structure to act on.
+      // Elfutils doesn't really have any particular function to
+      // access segment data, other than the functions used to
+      // access section data.
+      Elf_Scn *dynamic_section = gelf_offscn(elf, phdr->p_offset);
+      GElf_Shdr  shdr_mem;
+      GElf_Shdr *dynamic_section_header = gelf_getshdr(dynamic_section,
+						       &shdr_mem);
+      if (dynamic_section_header == NULL
+          || dynamic_section_header->sh_type != SHT_DYNAMIC)
+        continue;
+
+      // Get data of the dynamic segment (seen as a section).
+      Elf_Data *data = elf_getdata(dynamic_section, NULL);
+      if (data == NULL)
+        continue;
+
+      // Get the index of the section headers string table.
+      size_t string_table_index = 0;
+      ABG_ASSERT (elf_getshdrstrndx(elf, &string_table_index) >= 0);
+
+      size_t dynamic_section_header_entry_size = gelf_fsize(elf,
+                                                            ELF_T_DYN, 1,
+                                                            EV_CURRENT);
+
+      GElf_Shdr link_mem;
+      GElf_Shdr *link =
+        gelf_getshdr(elf_getscn(elf,
+                                dynamic_section_header->sh_link),
+		     &link_mem);
+      ABG_ASSERT(link != NULL);
+
+      size_t num_dynamic_section_entries =
+        dynamic_section_header->sh_size / dynamic_section_header_entry_size;
+
+      // Now walk through all the DT_* data tags that are in the
+      // segment/section
+      for (size_t j = 0; j < num_dynamic_section_entries; ++j)
+        {
+          GElf_Dyn dynamic_section_mem;
+          GElf_Dyn *dynamic_section = gelf_getdyn(data,
+                                                  j,
+                                                  &dynamic_section_mem);
+          if (dynamic_section->d_tag == data_tag)
+            {
+              dt_tag_data.push_back(elf_strptr(elf,
+                                               dynamic_section_header->sh_link,
+					       dynamic_section->d_un.d_val));
+              found = true;
+            }
+        }
+    }
+  return found;
+}
+
+const Dwfl_Callbacks&
+initialize_dwfl_callbacks(Dwfl_Callbacks& cb,
+			  char** debug_info_root_path)
+{
+  cb.find_debuginfo = dwfl_standard_find_debuginfo;
+  cb.section_address = dwfl_offline_section_address;
+  cb.debuginfo_path = debug_info_root_path;
+  return cb;
+}
+
+dwfl_sptr
+create_new_dwfl_handle(Dwfl_Callbacks& cb)
+{
+  dwfl_sptr handle(dwfl_begin(&cb), dwfl_deleter());
+  return handle;
+}
+
+/// Fetch the SONAME ELF property from an ELF binary file.
+///
+/// @param path The path to the elf file to consider.
+///
+/// @param soname out parameter. Set to the SONAME property of the
+/// binary file, if it present in the ELF file.
+///
+/// return false if an error occured while looking for the SONAME
+/// property in the binary, true otherwise.
+bool
+get_soname_of_elf_file(const string& path, string &soname)
+{
+
+  int fd = open(path.c_str(), O_RDONLY);
+  if (fd == -1)
+    return false;
+
+  elf_version (EV_CURRENT);
+  Elf* elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
+
+  GElf_Ehdr ehdr_mem;
+  GElf_Ehdr* ehdr = gelf_getehdr (elf, &ehdr_mem);
+  if (ehdr == NULL)
+    return false;
+
+  for (int i = 0; i < ehdr->e_phnum; ++i)
+    {
+      GElf_Phdr phdr_mem;
+      GElf_Phdr* phdr = gelf_getphdr (elf, i, &phdr_mem);
+
+      if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
+        {
+          Elf_Scn* scn = gelf_offscn (elf, phdr->p_offset);
+          GElf_Shdr shdr_mem;
+          GElf_Shdr* shdr = gelf_getshdr (scn, &shdr_mem);
+          size_t entsize = (shdr != NULL && shdr->sh_entsize != 0
+                            ? shdr->sh_entsize
+                            : gelf_fsize (elf, ELF_T_DYN, 1, EV_CURRENT));
+          int maxcnt = (shdr != NULL
+                        ? shdr->sh_size / entsize : INT_MAX);
+          ABG_ASSERT (shdr == NULL || (shdr->sh_type == SHT_DYNAMIC
+				       || shdr->sh_type == SHT_PROGBITS));
+          Elf_Data* data = elf_getdata (scn, NULL);
+          if (data == NULL)
+            break;
+
+          for (int cnt = 0; cnt < maxcnt; ++cnt)
+            {
+              GElf_Dyn dynmem;
+              GElf_Dyn* dyn = gelf_getdyn (data, cnt, &dynmem);
+              if (dyn == NULL)
+                continue;
+
+              if (dyn->d_tag == DT_NULL)
+                break;
+
+              if (dyn->d_tag != DT_SONAME)
+                continue;
+
+              soname = elf_strptr (elf, shdr->sh_link, dyn->d_un.d_val);
+              break;
+            }
+          break;
+        }
+    }
+
+  elf_end(elf);
+  close(fd);
+
+  return true;
+}
 
 } // end namespace elf_helpers
 } // end namespace abigail
diff --git a/src/abg-elf-helpers.h b/src/abg-elf-helpers.h
index e884c6a3..b0b105de 100644
--- a/src/abg-elf-helpers.h
+++ b/src/abg-elf-helpers.h
@@ -24,6 +24,27 @@ namespace abigail
 namespace elf_helpers
 {
 
+/// A functor used by @ref dwfl_sptr.
+struct dwfl_deleter
+{
+  void
+  operator()(Dwfl* dwfl)
+  {dwfl_end(dwfl);}
+};//end struct dwfl_deleter
+
+/// A convenience typedef for a shared pointer to a Dwfl.
+typedef shared_ptr<Dwfl> dwfl_sptr;
+
+/// Convenience typedef for a map which key is an elf address and
+/// which value is an elf_symbol_sptr.
+typedef unordered_map<GElf_Addr, elf_symbol_sptr> addr_elf_symbol_sptr_map_type;
+
+/// Convenience typedef for a set of ELF addresses.
+typedef unordered_set<GElf_Addr> address_set_type;
+
+/// Convenience typedef for a shared pointer to an @ref address_set_type.
+typedef shared_ptr<address_set_type> address_set_sptr;
+
 //
 // ELF Value Converters
 //
@@ -173,6 +194,16 @@ is_linux_kernel_module(Elf *elf_handle);
 bool
 is_linux_kernel(Elf *elf_handle);
 
+//
+// elfutils helpers
+//
+
+const Dwfl_Callbacks&
+initialize_dwfl_callbacks(Dwfl_Callbacks&, char**);
+
+dwfl_sptr
+create_new_dwfl_handle(Dwfl_Callbacks&);
+
 //
 // Misc Helpers
 //
@@ -195,6 +226,13 @@ maybe_adjust_et_rel_sym_addr_to_abs_addr(Elf* elf_handle, GElf_Sym* sym);
 bool
 address_is_in_opd_section(Elf* elf_handle, Dwarf_Addr addr);
 
+bool
+lookup_data_tag_from_dynamic_segment(Elf*                       elf,
+                                     Elf64_Sxword               data_tag,
+                                     vector<string>&            dt_tag_data);
+
+bool
+get_soname_of_elf_file(const string& path, string &soname);
 } // end namespace elf_helpers
 } // end namespace abigail
 
diff --git a/src/abg-elf-reader-common.cc b/src/abg-elf-reader-common.cc
deleted file mode 100644
index 1d0aff15..00000000
--- a/src/abg-elf-reader-common.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-// -*- Mode: C++ -*-
-//
-// Copyright (C) 2013-2022 Oracle, Inc.
-//
-// Author: Jose E. Marchesi
-
-/// @file
-///
-/// This file contains the implementation of facilities to deal with
-/// status codes related to ELF based readers.
-///
-/// More generally, this file contains definitions related to
-/// facilities shared by the various readers that handle the ELF
-/// format, e.g, the DWARF and CTF realder.
-#include "config.h"
-
-#include "abg-internal.h"
-
-// <headers defining libabigail's API go under here>
-ABG_BEGIN_EXPORT_DECLARATIONS
-
-#include "abg-elf-reader-common.h"
-
-ABG_END_EXPORT_DECLARATIONS
-// </headers defining libabigail's API>
-
-namespace abigail
-{
-
-namespace elf_reader
-{
-
-status
-operator|(status l, status r)
-{
-  return static_cast<status>(static_cast<unsigned>(l)
-			     | static_cast<unsigned>(r));
-}
-
-status
-operator&(status l, status r)
-{
-  return static_cast<status>(static_cast<unsigned>(l)
-			     & static_cast<unsigned>(r));
-}
-
-status&
-operator|=(status& l, status r)
-{
-  l = l | r;
-  return l;
-}
-
-status&
-operator&=(status& l, status r)
-{
-  l = l & r;
-  return l;
-}
-
-/// Return a diagnostic status with english sentences to describe the
-/// problems encoded in a given abigail::elf_reader::status, if
-/// there is an error.
-///
-/// @param status the status to diagnose
-///
-/// @return a string containing sentences that describe the possible
-/// errors encoded in @p s.  If there is no error to encode, then the
-/// empty string is returned.
-std::string
-status_to_diagnostic_string(status s)
-{
-  std::string str;
-
-  if (s & STATUS_DEBUG_INFO_NOT_FOUND)
-    str += "could not find debug info\n";
-
-  if (s & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
-    str += "could not find alternate debug info\n";
-
-  if (s & STATUS_NO_SYMBOLS_FOUND)
-    str += "could not load ELF symbols\n";
-
-  return str;
-}
-
-}// end namespace elf_reader
-
-}// end namespace abigail
diff --git a/src/abg-elf-reader.cc b/src/abg-elf-reader.cc
new file mode 100644
index 00000000..346d17a2
--- /dev/null
+++ b/src/abg-elf-reader.cc
@@ -0,0 +1,890 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// -*- Mode: C++ -*-
+//
+// Copyright (C) 2022 Red Hat, Inc.
+//
+// Author: Dodji Seketeli
+
+/// @file
+///
+/// Elf reader stuff
+
+#include "abg-internal.h"
+
+#include <fcntl.h> /* For open(3) */
+#include <unistd.h>
+#include <iostream>
+#include <cstring>
+#include <libgen.h>
+#include <fcntl.h>
+#include <elfutils/libdwfl.h>
+
+
+#include "abg-symtab-reader.h"
+#include "abg-suppression-priv.h"
+#include "abg-elf-helpers.h"
+
+// <headers defining libabigail's API go under here>
+ABG_BEGIN_EXPORT_DECLARATIONS
+#include "abg-elf-reader.h"
+#include "abg-tools-utils.h"
+ABG_END_EXPORT_DECLARATIONS
+// </headers defining libabigail's API>
+namespace abigail
+{
+
+using namespace elf_helpers;
+
+namespace elf_reader
+{
+
+/// Find the file name of the alternate debug info file.
+///
+/// @param elf_module the elf module to consider.
+///
+/// @param out parameter.  Is set to the file name of the alternate
+/// debug info file, iff this function returns true.
+///
+/// @return true iff the location of the alternate debug info file was
+/// found.
+static bool
+find_alt_dwarf_debug_info_link(Dwfl_Module *elf_module,
+			       string &alt_file_name)
+{
+  GElf_Addr bias = 0;
+  Dwarf *dwarf = dwfl_module_getdwarf(elf_module, &bias);
+  Elf *elf = dwarf_getelf(dwarf);
+  GElf_Ehdr ehmem, *elf_header;
+  elf_header = gelf_getehdr(elf, &ehmem);
+
+  Elf_Scn* section = 0;
+  while ((section = elf_nextscn(elf, section)) != 0)
+    {
+      GElf_Shdr header_mem, *header;
+      header = gelf_getshdr(section, &header_mem);
+      if (header->sh_type != SHT_PROGBITS)
+	continue;
+
+      const char *section_name = elf_strptr(elf,
+					    elf_header->e_shstrndx,
+					    header->sh_name);
+
+      char *alt_name = 0;
+      char *buildid = 0;
+      size_t buildid_len = 0;
+      if (section_name != 0
+	  && strcmp(section_name, ".gnu_debugaltlink") == 0)
+	{
+	  Elf_Data *data = elf_getdata(section, 0);
+	  if (data != 0 && data->d_size != 0)
+	    {
+	      alt_name = (char*) data->d_buf;
+	      char *end_of_alt_name =
+		(char *) memchr(alt_name, '\0', data->d_size);
+	      buildid_len = data->d_size - (end_of_alt_name - alt_name + 1);
+	      if (buildid_len == 0)
+		return false;
+	      buildid = end_of_alt_name + 1;
+	    }
+	}
+      else
+	continue;
+
+      if (buildid == 0 || alt_name == 0)
+	return false;
+
+      alt_file_name = alt_name;
+      return true;
+    }
+
+  return false;
+}
+
+/// Find alternate debuginfo file of a given "link" under a set of
+/// root directories.
+///
+/// The link is a string that is read by the function
+/// find_alt_dwarf_debug_info_link().  That link is a path that is relative
+/// to a given debug info file, e.g, "../../../.dwz/something.debug".
+/// It designates the alternate debug info file associated to a given
+/// debug info file.
+///
+/// This function will thus try to find the .dwz/something.debug file
+/// under some given root directories.
+///
+/// @param root_dirs the set of root directories to look from.
+///
+/// @param alt_file_name a relative path to the alternate debug info
+/// file to look for.
+///
+/// @param alt_file_path the resulting absolute path to the alternate
+/// debuginfo path denoted by @p alt_file_name and found under one of
+/// the directories in @p root_dirs.  This is set iff the function
+/// returns true.
+///
+/// @return true iff the function found the alternate debuginfo file.
+static bool
+find_alt_dwarf_debug_info_path(const vector<char**> root_dirs,
+			       const string &alt_file_name,
+			       string &alt_file_path)
+{
+  if (alt_file_name.empty())
+    return false;
+
+  string altfile_name = tools_utils::trim_leading_string(alt_file_name, "../");
+
+  for (vector<char**>::const_iterator i = root_dirs.begin();
+       i != root_dirs.end();
+       ++i)
+    if (tools_utils::find_file_under_dir(**i, altfile_name, alt_file_path))
+      return true;
+
+  return false;
+}
+
+/// Return the alternate debug info associated to a given main debug
+/// info file.
+///
+/// @param elf_module the elf module to consider.
+///
+/// @param debug_root_dirs a set of root debuginfo directories under
+/// which too look for the alternate debuginfo file.
+///
+/// @param alt_file_name output parameter.  This is set to the file
+/// path of the alternate debug info file associated to @p elf_module.
+/// This is set iff the function returns a non-null result.
+///
+/// @param alt_fd the file descriptor used to access the alternate
+/// debug info.  If this parameter is set by the function, then the
+/// caller needs to fclose it, otherwise the file descriptor is going
+/// to be leaked.  Note however that on recent versions of elfutils
+/// where libdw.h contains the function dwarf_getalt(), this parameter
+/// is set to 0, so it doesn't need to be fclosed.
+///
+/// Note that the alternate debug info file is a DWARF extension as of
+/// DWARF 4 ans is decribed at
+/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
+///
+/// @return the alternate debuginfo, or null.  If @p alt_fd is
+/// non-zero, then the caller of this function needs to call
+/// dwarf_end() on the returned alternate debuginfo pointer,
+/// otherwise, it's going to be leaked.
+static Dwarf*
+find_alt_dwarf_debug_info(Dwfl_Module *elf_module,
+			  const vector<char**> debug_root_dirs,
+			  string& alt_file_name,
+			  int& alt_fd)
+{
+  if (elf_module == 0)
+    return 0;
+
+  Dwarf* result = 0;
+  find_alt_dwarf_debug_info_link(elf_module, alt_file_name);
+
+#ifdef LIBDW_HAS_DWARF_GETALT
+  // We are on recent versions of elfutils where the function
+  // dwarf_getalt exists, so let's use it.
+  Dwarf_Addr bias = 0;
+  Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
+  result = dwarf_getalt(dwarf);
+  alt_fd = 0;
+#else
+  // We are on an old version of elfutils where the function
+  // dwarf_getalt doesn't exist yet, so let's open code its
+  // functionality
+  char *alt_name = 0;
+  const char *file_name = 0;
+  void **user_data = 0;
+  Dwarf_Addr low_addr = 0;
+  char *alt_file = 0;
+
+  file_name = dwfl_module_info(elf_module, &user_data,
+			       &low_addr, 0, 0, 0, 0, 0);
+
+  alt_fd = dwfl_standard_find_debuginfo(elf_module, user_data,
+					file_name, low_addr,
+					alt_name, file_name,
+					0, &alt_file);
+
+  result = dwarf_begin(alt_fd, DWARF_C_READ);
+#endif
+
+  if (result == 0)
+    {
+      // So we didn't find the alternate debuginfo file from the
+      // information that is in the debuginfo file associated to
+      // elf_module.  Maybe the alternate debuginfo file is located
+      // under one of the directories in debug_root_dirs.  So let's
+      // look in there.
+      string alt_file_path;
+      if (!find_alt_dwarf_debug_info_path(debug_root_dirs,
+					  alt_file_name,
+					  alt_file_path))
+	return result;
+
+      // If we reach this point it means we have found the path to the
+      // alternate debuginfo file and it's in alt_file_path.  So let's
+      // open it and read it.
+      int fd = open(alt_file_path.c_str(), O_RDONLY);
+      if (fd == -1)
+	return result;
+      result = dwarf_begin(fd, DWARF_C_READ);
+
+#ifdef LIBDW_HAS_DWARF_GETALT
+      Dwarf_Addr bias = 0;
+      Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
+      dwarf_setalt(dwarf, result);
+#endif
+    }
+
+  return result;
+}
+
+/// Private data of the @ref elf_reader::reader type.
+struct reader::priv
+{
+  reader&				rdr;
+  Elf*					elf_handle		= nullptr;
+  Elf_Scn*				symtab_section		= nullptr;
+  string				elf_architecture;
+  vector<string>			dt_needed;
+  // An abstraction of the symbol table.  This is loaded lazily, on
+  // demand.
+  mutable symtab_reader::symtab_sptr	symt;
+  // Where split debug info is to be searched for on disk.
+  vector<char**>			debug_info_root_paths;
+  // Some very useful callback functions that elfutils needs to
+  // perform various tasks.
+  Dwfl_Callbacks			offline_callbacks;
+  // A pointer to the DWARF Front End Library handle of elfutils.
+  // This is useful to perform all kind of things at a higher level.
+  dwfl_sptr				dwfl_handle;
+  // The address range of the offline elf file we are looking at.
+  Dwfl_Module*				elf_module		= nullptr;
+  // A pointer to the DWARF debug info, if found by locate_dwarf_debug_info.
+  Dwarf*				dwarf_handle		= nullptr;
+  // A pointer to the ALT DWARF debug info, which is the debug info
+  // that is constructed by the DWZ tool.  It's made of all the type
+  // information that was redundant in the DWARF.  DWZ put it there
+  // and make the DWARF reference it in here.
+  Dwarf*				alt_dwarf_handle	= nullptr;
+  string				alt_dwarf_path;
+  int					alt_dwarf_fd		= 0;
+  Elf_Scn*				ctf_section		= nullptr;
+  Elf_Scn*				alt_ctf_section	= nullptr;
+
+  priv(reader& reeder, const std::string& elf_path,
+       const vector<char**>& debug_info_roots)
+    : rdr(reeder)
+  {
+    rdr.corpus_path(elf_path);
+    initialize(debug_info_roots);
+  }
+
+  /// Reset the private data of @elf elf_reader::reader.
+  ///
+  /// @param debug_info_roots the vector of new directories where to
+  /// look for split debug info file.
+  void
+  initialize(const vector<char**>& debug_info_roots)
+  {
+    debug_info_root_paths = debug_info_roots;
+    symt.reset();
+    dwfl_handle.reset();
+    elf_module = nullptr;
+    elf_handle = nullptr;
+  }
+
+  /// Setup the necessary plumbing to open the ELF file and find all
+  /// the associated split debug info files.
+  ///
+  /// This function also setup the various handles on the opened ELF
+  /// file and whatnot.
+  void
+  crack_open_elf_file()
+  {
+    // Initialize the callback functions used by elfutils.
+    elf_helpers::initialize_dwfl_callbacks(offline_callbacks,
+					   debug_info_root_paths.empty()
+					   ? nullptr
+					   : debug_info_root_paths.front());
+
+    // Create a handle to the DWARF Front End Library that we'll need.
+    dwfl_handle = elf_helpers::create_new_dwfl_handle(offline_callbacks);
+
+    const string& elf_path = rdr.corpus_path();
+    // Get the set of addresses that make up the ELF file we are
+    // looking at.
+    elf_module =
+      dwfl_report_offline(dwfl_handle.get(),
+			  basename(const_cast<char*>(elf_path.c_str())),
+			  elf_path.c_str(), -1);
+    dwfl_report_end(dwfl_handle.get(), 0, 0);
+    ABG_ASSERT(elf_module);
+
+    // Finally, get and handle at the representation of the ELF file
+    // we've just cracked open.
+    GElf_Addr bias = 0;
+    elf_handle = dwfl_module_getelf(elf_module, &bias);
+    ABG_ASSERT(elf_handle);
+  }
+
+  /// Find the alternate debuginfo file associated to a given elf file.
+  ///
+  /// @param elf_module represents the elf file to consider.
+  ///
+  /// @param alt_file_name the resulting path to the alternate
+  /// debuginfo file found.  This is set iff the function returns a
+  /// non-nil value.
+  Dwarf*
+  find_alt_dwarf_debug_info(Dwfl_Module*	elf_module,
+			    string&		alt_file_name,
+			    int&		alt_fd)
+  {
+    Dwarf *result = 0;
+    result = elf_reader::find_alt_dwarf_debug_info(elf_module,
+						   debug_info_root_paths,
+						   alt_file_name, alt_fd);
+    return result;
+  }
+
+  /// Locate the DWARF debug info in the ELF file.
+  ///
+  /// This also knows how to locate split debug info.
+  void
+  locate_dwarf_debug_info()
+  {
+    ABG_ASSERT(dwfl_handle);
+
+    if (dwarf_handle)
+      return;
+
+    // First let's see if the ELF file that was cracked open does have
+    // some DWARF debug info embedded.
+    Dwarf_Addr bias = 0;
+    dwarf_handle = dwfl_module_getdwarf(elf_module, &bias);
+
+    // If no debug info was found in the binary itself, then look for
+    // split debuginfo files under multiple possible debuginfo roots.
+    for (vector<char**>::const_iterator i = debug_info_root_paths.begin();
+	 dwarf_handle == 0 && i != debug_info_root_paths.end();
+	 ++i)
+      {
+	offline_callbacks.debuginfo_path = *i;
+	dwarf_handle = dwfl_module_getdwarf(elf_module, &bias);
+      }
+
+    alt_dwarf_handle = find_alt_dwarf_debug_info(elf_module,
+						 alt_dwarf_path,
+						 alt_dwarf_fd);
+  }
+
+  /// Locate the CTF "alternate" debug information associated with the
+  /// current ELF file ( and split out somewhere else).
+  ///
+  /// This is a sub-routine of @ref locate_ctf_debug_info().
+  void
+  locate_alt_ctf_debug_info()
+  {
+    Elf_Scn *section =
+      elf_helpers::find_section(elf_handle,
+				".gnu_debuglink",
+				SHT_PROGBITS);
+
+    std::string name;
+    Elf_Data *data;
+    if (section
+	&& (data = elf_getdata(section, nullptr))
+	&& data->d_size != 0)
+      name = (char *) data->d_buf;
+
+    if (!name.empty())
+      for (const auto& path : rdr.debug_info_root_paths())
+	{
+	  std::string file_path;
+	  if (!tools_utils::find_file_under_dir(*path, name, file_path))
+	    continue;
+
+	  int fd;
+	  if ((fd = open(file_path.c_str(), O_RDONLY)) == -1)
+	    continue;
+
+	  Elf *hdl;
+	  if ((hdl = elf_begin(fd, ELF_C_READ, nullptr)) == nullptr)
+	    {
+	      close(fd);
+	      continue;
+	    }
+
+	  // unlikely .ctf was designed to be present in stripped file
+	  alt_ctf_section =
+	    elf_helpers::find_section(hdl, ".ctf", SHT_PROGBITS);
+          break;
+
+	  elf_end(hdl);
+	  close(fd);
+	}
+  }
+
+  /// Locate the CTF debug information associated with the current ELF
+  /// file.  It also locates the CTF debug information that is split
+  /// out in a separate file.
+  void
+  locate_ctf_debug_info()
+  {
+    ABG_ASSERT(elf_handle);
+
+    ctf_section = elf_helpers::find_section_by_name(elf_handle, ".ctf");
+    if (ctf_section == nullptr)
+      {
+	locate_alt_ctf_debug_info();
+	ctf_section = alt_ctf_section;
+      }
+  }
+}; //end reader::priv
+
+/// The constructor of the @ref elf_reader::reader type.
+///
+/// @param elf_path the path to the ELF file to read from.
+///
+/// @param debug_info_root a vector of directory paths to look into
+/// for split debug information files.
+///
+/// @param env the environment which the reader operates in.
+reader::reader(const string&		elf_path,
+	       const vector<char**>&	debug_info_roots,
+	       ir::environment&	env)
+  : fe_iface(elf_path, env),
+    priv_(new priv(*this, elf_path, debug_info_roots))
+{
+  priv_->crack_open_elf_file();
+  priv_->locate_dwarf_debug_info();
+}
+
+/// The destructor of the @ref elf_reader::reader type.
+reader::~reader()
+{delete priv_;}
+
+/// Resets (erase) the resources used by the current @ref
+/// elf_reader::reader type.
+///
+/// This lets the reader in a state where it's ready to read from
+/// another ELF file.
+///
+/// @param elf_path the new ELF path to read from.
+///
+/// @param debug_info_roots a vector of directory paths to look into
+/// for split debug information files.
+void
+reader::reset(const std::string&	elf_path,
+	      const vector<char**>&	debug_info_roots)
+{
+  corpus_path(elf_path);
+  priv_->initialize(debug_info_roots);
+  priv_->crack_open_elf_file();
+  priv_->locate_dwarf_debug_info();
+}
+
+/// Getter of the vector of directory paths to look into for split
+/// debug information files.
+///
+/// @return the vector of directory paths to look into for split
+/// debug information files.
+const vector<char**>&
+reader::debug_info_root_paths() const
+{return priv_->debug_info_root_paths;}
+
+/// Getter of the functions used by the DWARF Front End library of
+/// elfutils to locate DWARF debug information.
+///
+/// @return the functions used by the DWARF Front End library of
+const Dwfl_Callbacks&
+reader::dwfl_offline_callbacks() const
+{return priv_->offline_callbacks;}
+
+/// Getter of the functions used by the DWARF Front End library of
+/// elfutils to locate DWARF debug information.
+///
+/// @return the functions used by the DWARF Front End library of
+Dwfl_Callbacks&
+reader::dwfl_offline_callbacks()
+{return priv_->offline_callbacks;}
+
+/// Getter of the handle used to access ELF information from the
+/// current ELF file.
+///
+/// @return the handle used to access ELF information from the current
+/// ELF file.
+Elf*
+reader::elf_handle() const
+{return priv_->elf_handle;}
+
+/// Getter of the handle used to access DWARF information from the
+/// current ELF file.
+///
+/// @return the handle used to access DWARF information from the
+/// current ELF file.
+const Dwarf*
+reader::dwarf_debug_info() const
+{return priv_->dwarf_handle;}
+
+/// Getter of the handle use to access DWARF information from the
+/// alternate split DWARF information.
+///
+/// In other words, this accesses the factorized DWARF information
+/// that has been constructed by the DWZ tool to de-duplicate DWARF
+/// information on disk.
+///
+/// @return the handle use to access DWARF information from the
+/// alternate split DWARF information.
+const Dwarf*
+reader::alternate_dwarf_debug_info() const
+{return priv_->alt_dwarf_handle;}
+
+
+/// Getter of the path to the alternate split DWARF information file,
+/// on disk.  In othe words, this returns the path to the factorized
+/// DWARF information used by the current ELF file, created by the
+/// 'DWZ' tool.
+///
+/// @return the path to the alternate split DWARF information file,
+/// on disk.
+const string&
+reader::alternate_dwarf_debug_info_path() const
+{return priv_->alt_dwarf_path;}
+
+/// Check if the underlying elf file refers to an alternate debug info
+/// file associated to it.
+///
+/// Note that "alternate debug info sections" is a GNU extension as
+/// of DWARF4 and is described at
+/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
+///
+/// @param alt_di the path to the alternate debug info file.  This is
+/// set iff the function returns true.
+///
+/// @return true if the ELF file refers to an alternate debug info
+/// file.
+bool
+reader::refers_to_alt_debug_info(string& alt_di_path) const
+{
+  if (!alternate_dwarf_debug_info_path().empty())
+    {
+      alt_di_path = alternate_dwarf_debug_info_path();
+      return true;
+    }
+  return false;
+}
+
+/// Find and return a pointer to the ELF symbol table
+/// section.
+///
+/// @return a pointer to the ELF symbol table section.
+const Elf_Scn*
+reader::find_symbol_table_section() const
+{
+  if (!priv_->symtab_section)
+      priv_->symtab_section =
+	elf_helpers::find_symbol_table_section(elf_handle());
+    return priv_->symtab_section;
+}
+
+/// Clear the pointer to the ELF symbol table section.
+void
+reader::reset_symbol_table_section()
+{priv_->symtab_section = nullptr;}
+
+/// Find and return a pointer to the the CTF section.
+///
+/// @return a pointer to the the CTF section.
+const Elf_Scn*
+reader::find_ctf_section() const
+{
+  if (priv_->ctf_section == nullptr)
+    priv_->locate_ctf_debug_info();
+
+  if (priv_->ctf_section)
+    return priv_->ctf_section;
+
+  return priv_->alt_ctf_section;
+}
+
+/// Find and return a pointer to the alternate CTF section of the
+/// current ELF file.
+///
+/// @return a pointer to the alternate CTF section of the current ELF
+/// file.
+const Elf_Scn*
+reader::find_alternate_ctf_section() const
+{
+  if (priv_->alt_ctf_section == nullptr)
+    priv_->locate_alt_ctf_debug_info();
+
+  return priv_->alt_ctf_section;
+}
+
+/// Get the value of the DT_NEEDED property of the current ELF file.
+///
+/// @return the value of the DT_NEEDED property.
+const vector<string>&
+reader::dt_needed()const
+{return priv_->dt_needed;}
+
+
+/// Get the value of the 'ARCHITECTURE' property of the current ELF file.
+///
+/// @return the value of the 'ARCHITECTURE' property of the current
+/// ELF file.
+const string&
+reader::elf_architecture() const
+{return priv_->elf_architecture;}
+
+/// Getter of an abstract representation of the symbol table of the
+/// underlying ELF file.
+///
+/// Note that the symbol table is loaded lazily, upon the first
+/// invocation of this member function.
+///
+/// @returnt the symbol table.
+symtab_reader::symtab_sptr&
+reader::symtab() const
+{
+  ABG_ASSERT(elf_handle());
+
+  if (!priv_->symt)
+    priv_->symt = symtab_reader::symtab::load
+      (elf_handle(), options().env,
+       [&](const elf_symbol_sptr& symbol)
+       {return suppr::is_elf_symbol_suppressed(*this, symbol);});
+
+  if (!priv_->symt)
+    std::cerr << "Symbol table of '" << corpus_path()
+	      << "' could not be loaded\n";
+  return priv_->symt;
+}
+
+/// Test if a given function symbol has been exported.
+///
+/// @param symbol_address the address of the symbol we are looking
+/// for.  Note that this address must be a relative offset from the
+/// beginning of the .text section, just like the kind of addresses
+/// that are present in the .symtab section.
+///
+/// @returnthe elf symbol if found, or nil otherwise.
+elf_symbol_sptr
+reader::function_symbol_is_exported(GElf_Addr symbol_address) const
+{
+  elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
+  if (!symbol)
+    return symbol;
+
+  if (!symbol->is_function() || !symbol->is_public())
+    return elf_symbol_sptr();
+
+  address_set_sptr set;
+  bool looking_at_linux_kernel_binary =
+    load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
+
+  if (looking_at_linux_kernel_binary)
+    {
+	if (symbol->is_in_ksymtab())
+	  return symbol;
+	return elf_symbol_sptr();
+    }
+
+  return symbol;
+}
+
+/// Test if a given variable symbol has been exported.
+///
+/// @param symbol_address the address of the symbol we are looking
+/// for.  Note that this address must be a relative offset from the
+/// beginning of the .text section, just like the kind of addresses
+/// that are present in the .symtab section.
+///
+/// @returnthe elf symbol if found, or nil otherwise.
+elf_symbol_sptr
+reader::variable_symbol_is_exported(GElf_Addr symbol_address) const
+{
+  elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
+  if (!symbol)
+    return symbol;
+
+  if (!symbol->is_variable() || !symbol->is_public())
+    return elf_symbol_sptr();
+
+  address_set_sptr set;
+  bool looking_at_linux_kernel_binary =
+    load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
+
+  if (looking_at_linux_kernel_binary)
+    {
+	if (symbol->is_in_ksymtab())
+	  return symbol;
+	return elf_symbol_sptr();
+    }
+
+  return symbol;
+}
+
+/// Load the DT_NEEDED and DT_SONAME elf TAGS.
+void
+reader::load_dt_soname_and_needed()
+{
+  elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
+						    DT_NEEDED,
+						    priv_->dt_needed);
+
+  vector<string> dt_tag_data;
+  elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
+						    DT_SONAME,
+						    dt_tag_data);
+  if (!dt_tag_data.empty())
+    dt_soname(dt_tag_data[0]);
+}
+
+/// Read the string representing the architecture of the current ELF
+/// file.
+void
+reader::load_elf_architecture()
+{
+  if (!elf_handle())
+    return;
+
+  GElf_Ehdr eh_mem;
+  GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
+
+  priv_->elf_architecture =
+    elf_helpers::e_machine_to_string(elf_header->e_machine);
+}
+
+/// Load various ELF data.
+///
+/// This function loads ELF data that are not symbol maps or debug
+/// info.  That is, things like various tags, elf architecture and
+/// so on.
+void
+reader::load_elf_properties()
+{
+  // Note that we don't load the symbol table as it's loaded lazily,
+  // on demand.
+
+  load_dt_soname_and_needed();
+  load_elf_architecture();
+}
+
+/// Read the ELF information associated to the current ELF file and
+/// construct an ABI representation from it.
+///
+/// Note that this reader doesn't know how to interpret any debug
+/// information so the resulting ABI corpus won't have any type
+/// information.  Rather, it will only have ELF symbol representation.
+///
+/// To have type information, consider using readers that know how to
+/// interpret the symbolic type information comprised in DWARF, CTF or
+/// other symbolic debug information format, like the @ref or
+/// abigail::dwarf_reader::reader, @ref abigail::ctf_reader::reader
+/// readers.
+///
+/// @return the resulting ABI corpus.
+ir::corpus_sptr
+reader::read_corpus(status& status)
+{
+  status = STATUS_UNKNOWN;
+
+  load_elf_properties(); // DT_SONAME, DT_NEEDED, architecture
+  corpus()->set_soname(dt_soname());
+  corpus()->set_needed(dt_needed());
+  corpus()->set_architecture_name(elf_architecture());
+
+  // See if we could find symbol tables.
+  if (!symtab() || !symtab()->has_symbols())
+    {
+      status |= STATUS_NO_SYMBOLS_FOUND;
+      // We found no ELF symbol, so we can't handle the binary.
+      return corpus_sptr();
+    }
+
+  // Set symbols information to the corpus.
+  corpus()->set_symtab(symtab());
+
+  // If we couldn't load debug info from the elf path, then say it.
+    if (dwarf_debug_info() == nullptr
+	&& find_ctf_section() == nullptr)
+      status |= STATUS_DEBUG_INFO_NOT_FOUND;
+
+    status |= STATUS_OK;
+
+    return corpus();
+}
+
+/// Get the SONAME property of a designated ELF file.
+///
+/// @param path the path to the ELF file to consider.
+///
+/// @param soname output parameter.  This is set to the SONAME of the
+/// file located at @p path, iff this function return true.
+///
+/// @return true iff the SONAME property was found in the ELF file
+/// located at @p path and set into the argument of the parameter @p
+/// soname.
+bool
+get_soname_of_elf_file(const string& path, string &soname)
+{return elf_helpers::get_soname_of_elf_file(path, soname);}
+
+/// Convert the type of ELF file into @ref elf_type.
+///
+/// @param elf the elf handle to use for the query.
+///
+/// @return the @ref elf_type for a given elf type.
+static elf_reader::elf_type
+elf_file_type(Elf* elf)
+{
+  GElf_Ehdr ehdr_mem;
+  GElf_Ehdr *header = gelf_getehdr (elf, &ehdr_mem);
+  vector<string> dt_debug_data;
+
+  switch (header->e_type)
+    {
+    case ET_DYN:
+      if (lookup_data_tag_from_dynamic_segment(elf, DT_DEBUG, dt_debug_data))
+	return elf_reader::ELF_TYPE_PI_EXEC;
+      else
+	return elf_reader::ELF_TYPE_DSO;
+    case ET_EXEC:
+      return elf_reader::ELF_TYPE_EXEC;
+    case ET_REL:
+      return elf_reader::ELF_TYPE_RELOCATABLE;
+    default:
+      return elf_reader::ELF_TYPE_UNKNOWN;
+    }
+}
+
+/// Get the type of a given elf type.
+///
+/// @param path the absolute path to the ELF file to analyzed.
+///
+/// @param type the kind of the ELF file designated by @p path.
+///
+/// @param out parameter.  Is set to the type of ELF file of @p path.
+/// This parameter is set iff the function returns true.
+///
+/// @return true iff the file could be opened and analyzed.
+bool
+get_type_of_elf_file(const string& path, elf_reader::elf_type& type)
+{
+  int fd = open(path.c_str(), O_RDONLY);
+  if (fd == -1)
+    return false;
+
+  elf_version (EV_CURRENT);
+  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
+  type = elf_file_type(elf);
+  elf_end(elf);
+  close(fd);
+
+  return true;
+}
+
+}// end namespace elf_reader
+} // end namespace abigail
diff --git a/src/abg-fe-iface.cc b/src/abg-fe-iface.cc
new file mode 100644
index 00000000..88993248
--- /dev/null
+++ b/src/abg-fe-iface.cc
@@ -0,0 +1,411 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// -*- Mode: C++ -*-
+//
+// Copyright (C) 2022 Red Hat, Inc.
+//
+// Author: Dodji Seketeli
+
+/// @file
+///
+/// This file contains the definitions of the the fe_iface base type.
+
+#include "abg-internal.h"
+// <headers defining libabigail's API go under here>
+ABG_BEGIN_EXPORT_DECLARATIONS
+
+#include "abg-corpus.h"
+#include "abg-fe-iface.h"
+
+ABG_END_EXPORT_DECLARATIONS
+// </headers defining libabigail's API>
+
+namespace abigail
+{
+
+/// The private data structure for the @ref fe_iface type.
+struct fe_iface::priv
+{
+  std::string corpus_path;
+  std::string dt_soname;
+  fe_iface::options_type options;
+  suppr::suppressions_type suppressions;
+  ir::corpus_sptr corpus;
+  ir::corpus_group_sptr corpus_group;
+
+  priv(const std::string& path, environment& e)
+    : corpus_path(path), options(e)
+  {
+    initialize();
+  }
+
+  /// This function resets the data of @ref fe_iface::priv data so
+  /// that it can be re-used again.
+  void
+  initialize()
+  {
+    //TODO: initialize the options.
+    corpus_path.clear();
+    dt_soname.clear();
+    suppressions.clear();
+    corpus_group.reset();
+  }
+}; //end struct fe_iface::priv
+
+/// Constructor of the type @ref fe_iface::options_type.
+///
+/// @param e the environment used by the Front End Interface.
+fe_iface::options_type::options_type(environment& e)
+  : env(e)
+{
+}
+
+/// Constructor of the type @ref fe_iface.
+///
+/// @param corpus_path the path to the file represented by the ABI
+/// corpus that is going to be built by this Front End.
+///
+/// @param e the environment in which the Front End operates.
+fe_iface::fe_iface(const std::string& corpus_path, environment& e)
+  : priv_(new priv(corpus_path, e))
+{
+}
+
+/// Desctructor of the Front End Interface.
+fe_iface::~fe_iface()
+{delete priv_;}
+
+/// Re-initialize the current Front End.
+///
+/// @param corpus_path the path to the file for which a new corpus is
+/// to be created.
+///
+/// @param e the environment in which the Front End operates.
+void
+fe_iface::reset(const std::string& corpus_path,
+		environment& e)
+{
+  delete priv_;
+  priv_ = new fe_iface::priv(corpus_path, e);
+}
+
+/// Getter of the the options of the current Front End Interface.
+///
+/// @return the options of the current Front End Interface.
+const fe_iface::options_type&
+fe_iface::options() const
+{return priv_->options;}
+
+/// Getter of the the options of the current Front End Interface.
+///
+/// @return the options of the current Front End Interface.
+fe_iface::options_type&
+fe_iface::options()
+{return priv_->options;}
+
+/// Getter of the path to the file which an ABI corpus is to be
+/// created for.
+///
+/// @return the path to the file which an ABI corpus is to be created
+/// for.
+const std::string&
+fe_iface::corpus_path() const
+{return priv_->corpus_path;}
+
+/// Setter of the path to the file which an ABI corpus is to be
+/// created for.
+///
+/// @param p the new path to the file which an ABI corpus is to be
+/// created for.
+void
+fe_iface::corpus_path(const std::string& p)
+{priv_->corpus_path = p;}
+
+/// Getter for the SONAME of the analyzed binary.
+///
+/// @return the SONAME of the analyzed binary.
+const string&
+fe_iface::dt_soname() const
+{return priv_->dt_soname;}
+
+/// Getter for the SONAME of the analyzed binary.
+///
+/// @return the SONAME of the analyzed binary.
+void
+fe_iface::dt_soname(const string& soname)
+{priv_->dt_soname = soname;}
+
+/// Test if the input binary is to be considered as a Linux Kernel
+/// binary.
+///
+/// @return true iff the input binary is to be considered as a Linux
+/// Kernel binary.
+bool
+fe_iface::load_in_linux_kernel_mode() const
+{return priv_->options.load_in_linux_kernel_mode;}
+
+/// Getter of the vector of suppression specifications associated with
+/// the current front-end.
+///
+/// @return the vector of suppression specifications associated with
+/// the current front-end.
+suppr::suppressions_type&
+fe_iface::suppressions()
+{return priv_->suppressions;}
+
+/// Getter of the vector of suppression specifications associated with
+/// the current front-end.
+///
+/// @return the vector of suppression specifications associated with
+/// the current front-end.
+const suppr::suppressions_type&
+fe_iface::suppressions() const
+{return priv_->suppressions;}
+
+/// Setter of the vector of suppression specifications associated with
+/// the current front-end.
+///
+/// @param supprs the new vector of suppression specifications
+/// associated with the current front-end.
+void
+fe_iface::suppressions(suppr::suppressions_type& supprs)
+{priv_->suppressions = supprs;}
+
+/// Add suppressions specifications to the set of suppressions to be
+/// used during the construction of the ABI internal representation
+/// (the ABI corpus) from the input file.
+///
+/// During the construction of the ABI corpus, ABI artifacts that
+/// match a given suppression specification are dropped on the floor;
+/// that is, they are discarded and won't be part of the final ABI
+/// corpus.  This is a way to reduce the amount of data held by the
+/// final ABI corpus.
+///
+/// Note that the suppression specifications provided to this function
+/// are only considered during the construction of the ABI corpus.
+/// For instance, they are not taken into account during e.g
+/// comparisons of two ABI corpora that might happen later.  If you
+/// want to apply suppression specificatins to the comparison (or
+/// reporting) of ABI corpora please refer to the documentation of the
+/// @ref diff_context type to learn how to set suppressions that are
+/// to be used in that context.
+///
+/// @param supprs the suppression specifications to be applied during
+/// the construction of the ABI corpus.
+void
+fe_iface::add_suppressions(const suppr::suppressions_type& supprs)
+{
+  for (const auto& s : supprs)
+    if (s->get_drops_artifact_from_ir())
+      suppressions().push_back(s);
+}
+
+/// Getter for the ABI corpus being built by the current front-end.
+///
+/// @return the ABI corpus being built by the current front-end.
+corpus_sptr
+fe_iface::corpus()
+{
+  if (!priv_->corpus)
+    {
+      priv_->corpus = std::make_shared<ir::corpus>(options().env,
+						   corpus_path());
+    }
+  return priv_->corpus;
+}
+
+/// Getter for the ABI corpus being built by the current front-end.
+///
+/// @return the ABI corpus being built by the current front-end.
+const corpus_sptr
+fe_iface::corpus() const
+{return const_cast<fe_iface*>(this)->corpus();}
+
+/// Getter for the ABI corpus group being built by the current front-end.
+///
+/// @return the ABI corpus group being built by the current front-end.
+corpus_group_sptr&
+fe_iface::corpus_group()
+{return priv_->corpus_group;}
+
+/// Getter for the ABI corpus group being built by the current front-end.
+///
+/// @return the ABI corpus group being built by the current front-end.
+const corpus_group_sptr&
+fe_iface::corpus_group() const
+{return const_cast<fe_iface*>(this)->corpus_group();}
+
+/// Setter for the ABI corpus group being built by the current
+/// front-end.
+///
+/// @param cg the new ABI corpus group being built by the current
+/// front-end.
+void
+fe_iface::corpus_group(const ir::corpus_group_sptr& cg)
+{priv_->corpus_group = cg;}
+
+/// Test if there is a corpus group being built.
+///
+/// @return if there is a corpus group being built, false otherwise.
+bool
+fe_iface::has_corpus_group() const
+{return bool(corpus_group());}
+
+/// Return the main corpus from the current corpus group, if any.
+///
+/// @return the main corpus of the current corpus group, if any, nil
+/// if no corpus group is being constructed.
+corpus_sptr
+fe_iface::main_corpus_from_current_group()
+{
+  if (corpus_group())
+    return corpus_group()->get_main_corpus();
+  return corpus_sptr();
+}
+
+/// Test if the current corpus being built is the main corpus of the
+/// current corpus group.
+///
+/// @return return true iff the current corpus being built is the
+/// main corpus of the current corpus group.
+bool
+fe_iface::current_corpus_is_main_corpus_from_current_group()
+{
+  corpus_sptr main_corpus = main_corpus_from_current_group();
+
+  if (main_corpus.get() == corpus().get())
+    return true;
+
+  return false;
+}
+
+/// Return true if the current corpus is part of a corpus group
+/// being built and if it's not the main corpus of the group.
+///
+/// For instance, this would return true if we are loading a linux
+/// kernel *module* that is part of the current corpus group that is
+/// being built.  In this case, it means we should re-use types
+/// coming from the "vmlinux" binary that is the main corpus of the
+/// group.
+///
+/// @return the corpus group the current corpus belongs to, if the
+/// current corpus is part of a corpus group being built. Nil otherwise.
+corpus_sptr
+fe_iface::should_reuse_type_from_corpus_group()
+{
+  if (has_corpus_group())
+    if (corpus_sptr main_corpus = main_corpus_from_current_group())
+	if (!current_corpus_is_main_corpus_from_current_group())
+	  return corpus_group();
+
+  return corpus_sptr();
+}
+
+/// Try and add the representation of the ABI of a function to the set
+/// of exported declarations of the current corpus.
+///
+/// @param fn the internal representation of the ABI of a function.
+void
+fe_iface::maybe_add_fn_to_exported_decls(const function_decl* fn)
+{
+  if (fn)
+    if (corpus::exported_decls_builder* b =
+	corpus()->get_exported_decls_builder().get())
+      b->maybe_add_fn_to_exported_fns(fn);
+}
+
+/// Try and add the representation of the ABI of a variable to the set
+/// of exported declarations of the current corpus.
+///
+/// @param var the internal representation of the ABI of a variable.
+void
+fe_iface::maybe_add_var_to_exported_decls(const var_decl* var)
+{
+  if (var)
+    if (corpus::exported_decls_builder* b =
+	corpus()->get_exported_decls_builder().get())
+      b->maybe_add_var_to_exported_vars(var);
+}
+
+/// The bitwise OR operator for the @ref fe_iface::status type.
+///
+/// @param l the left-hand side operand.
+///
+/// @param r the right-hand side operand.
+///
+/// @return the result of the operation.
+fe_iface::status
+operator|(fe_iface::status l, fe_iface::status r)
+{
+  return static_cast<fe_iface::status>(static_cast<unsigned>(l)
+				       | static_cast<unsigned>(r));
+}
+
+/// The bitwise AND operator for the @ref fe_iface::status type.
+///
+/// @param l the left-hand side operand.
+///
+/// @param r the right-hand side operand.
+///
+/// @return the result of the operation.
+fe_iface::status
+operator&(fe_iface::status l, fe_iface::status r)
+{
+  return static_cast<fe_iface::status>(static_cast<unsigned>(l)
+				       & static_cast<unsigned>(r));
+}
+
+/// The bitwise |= operator for the @ref fe_iface::status type.
+///
+/// @param l the left-hand side operand.
+///
+/// @param r the right-hand side operand.
+///
+/// @return the result of the operation.
+fe_iface::status&
+operator|=(fe_iface::status& l, fe_iface::status r)
+{
+  l = l | r;
+  return l;
+}
+
+/// The bitwise &= operator for the @ref fe_iface::status type.
+///
+/// @param l the left-hand side operand.
+///
+/// @param r the right-hand side operand.
+///
+/// @return the result of the operation.
+fe_iface::status&
+operator&=(fe_iface::status& l, fe_iface::status r)
+{
+  l = l & r;
+  return l;
+}
+
+/// Return a diagnostic status with english sentences to describe the
+/// problems encoded in a given abigail::elf_reader::status, if
+/// there is an error.
+///
+/// @param status the status to diagnose
+///
+/// @return a string containing sentences that describe the possible
+/// errors encoded in @p s.  If there is no error to encode, then the
+/// empty string is returned.
+std::string
+status_to_diagnostic_string(fe_iface::status s)
+{
+  std::string str;
+
+  if (s & fe_iface::STATUS_DEBUG_INFO_NOT_FOUND)
+    str += "could not find debug info\n";
+
+  if (s & fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
+    str += "could not find alternate debug info\n";
+
+  if (s & fe_iface::STATUS_NO_SYMBOLS_FOUND)
+    str += "could not load ELF symbols\n";
+
+  return str;
+}
+
+}// namespace abigail
diff --git a/src/abg-ir-priv.h b/src/abg-ir-priv.h
index dd3c6276..32041d31 100644
--- a/src/abg-ir-priv.h
+++ b/src/abg-ir-priv.h
@@ -141,7 +141,7 @@ parse_integral_type(const string& type_name,
 /// Private type to hold private members of @ref translation_unit
 struct translation_unit::priv
 {
-  const environment*				env_;
+  const environment&				env_;
   corpus*					corp;
   bool						is_constructed_;
   char						address_size_;
@@ -156,7 +156,7 @@ struct translation_unit::priv
   type_maps					types_;
 
 
-  priv(const environment* env)
+  priv(const environment& env)
     : env_(env),
       corp(),
       is_constructed_(),
@@ -845,7 +845,7 @@ struct environment::priv
     for (auto i : types_with_non_confirmed_propagated_ct_)
       {
 	type_base *t = reinterpret_cast<type_base*>(i);
-	ABG_ASSERT(t->get_environment()->priv_->is_recursive_type(t)
+	ABG_ASSERT(t->get_environment().priv_->is_recursive_type(t)
 		   || t->priv_->depends_on_recursive_type());
 	t->priv_->set_does_not_depend_on_recursive_type(dependant_type);
 	if (!t->priv_->depends_on_recursive_type())
@@ -876,13 +876,12 @@ struct environment::priv
     if (!t || t->priv_->propagated_canonical_type_confirmed())
       return;
 
-    const environment* env = t->get_environment();
-    ABG_ASSERT(env);
+    const environment& env = t->get_environment();
 
-    env->priv_->confirm_ct_propagation_for_types_dependant_on(t);
+    env.priv_->confirm_ct_propagation_for_types_dependant_on(t);
     t->priv_->set_does_not_depend_on_recursive_type();
-    env->priv_->remove_from_types_with_non_confirmed_propagated_ct(t);
-    env->priv_->set_is_not_recursive(t);
+    env.priv_->remove_from_types_with_non_confirmed_propagated_ct(t);
+    env.priv_->set_is_not_recursive(t);
     t->priv_->set_propagated_canonical_type_confirmed(true);
   }
 
@@ -900,7 +899,7 @@ struct environment::priv
     for (auto i : types_with_non_confirmed_propagated_ct_)
       {
 	type_base *t = reinterpret_cast<type_base*>(i);
-	ABG_ASSERT(t->get_environment()->priv_->is_recursive_type(t)
+	ABG_ASSERT(t->get_environment().priv_->is_recursive_type(t)
 		   || t->priv_->depends_on_recursive_type());
 	t->priv_->set_does_not_depend_on_recursive_type();
 	t->priv_->set_propagated_canonical_type_confirmed(true);
@@ -970,7 +969,7 @@ struct environment::priv
     for (auto i : to_remove)
       {
 	type_base *t = reinterpret_cast<type_base*>(i);
-	ABG_ASSERT(t->get_environment()->priv_->is_recursive_type(t)
+	ABG_ASSERT(t->get_environment().priv_->is_recursive_type(t)
 		   || t->priv_->depends_on_recursive_type());
 	type_base_sptr canonical = t->priv_->canonical_type.lock();
 	if (canonical)
@@ -1007,10 +1006,10 @@ struct environment::priv
     if (!t)
       return;
 
-    const environment *env = t->get_environment();
-    env->priv_->cancel_ct_propagation_for_types_dependant_on(t);
+    const environment& env = t->get_environment();
+    env.priv_->cancel_ct_propagation_for_types_dependant_on(t);
     if (t->priv_->depends_on_recursive_type()
-	|| env->priv_->is_recursive_type(t))
+	|| env.priv_->is_recursive_type(t))
       {
 	// This cannot carry any tentative canonical type at this
 	// point.
@@ -1020,7 +1019,7 @@ struct environment::priv
 	// Reset the marking of the type as it no longer carries a
 	// tentative canonical type that might be later cancelled.
 	t->priv_->set_does_not_depend_on_recursive_type();
-	env->priv_->remove_from_types_with_non_confirmed_propagated_ct(t);
+	env.priv_->remove_from_types_with_non_confirmed_propagated_ct(t);
       }
   }
 
@@ -1174,9 +1173,8 @@ struct class_or_union::priv
   mark_as_being_compared(const class_or_union& first,
 			 const class_or_union& second) const
   {
-    const environment* env = first.get_environment();
-    ABG_ASSERT(env);
-    env->priv_->classes_being_compared_.insert
+    const environment& env = first.get_environment();
+    env.priv_->classes_being_compared_.insert
       (std::make_pair(reinterpret_cast<uint64_t>(&first),
 		      reinterpret_cast<uint64_t>(&second)));
   }
@@ -1237,9 +1235,8 @@ struct class_or_union::priv
   unmark_as_being_compared(const class_or_union& first,
 			   const class_or_union& second) const
   {
-    const environment* env = first.get_environment();
-    ABG_ASSERT(env);
-    env->priv_->classes_being_compared_.erase
+    const environment& env = first.get_environment();
+    env.priv_->classes_being_compared_.erase
       (std::make_pair(reinterpret_cast<uint64_t>(&first),
 		      reinterpret_cast<uint64_t>(&second)));
   }
@@ -1279,9 +1276,8 @@ struct class_or_union::priv
   comparison_started(const class_or_union& first,
 		     const class_or_union& second) const
   {
-    const environment* env = first.get_environment();
-    ABG_ASSERT(env);
-    return env->priv_->
+    const environment& env = first.get_environment();
+    return env.priv_->
       classes_being_compared_.count
       (std::make_pair(reinterpret_cast<uint64_t>(&first),
 		      reinterpret_cast<uint64_t>((&second))));
@@ -1340,9 +1336,8 @@ struct function_type::priv
   mark_as_being_compared(const function_type& first,
 			 const function_type& second) const
   {
-    const environment* env = first.get_environment();
-    ABG_ASSERT(env);
-    env->priv_->fn_types_being_compared_.insert
+    const environment& env = first.get_environment();
+    env.priv_->fn_types_being_compared_.insert
       (std::make_pair(reinterpret_cast<uint64_t>(&first),
 		      reinterpret_cast<uint64_t>(&second)));
   }
@@ -1358,9 +1353,8 @@ struct function_type::priv
   unmark_as_being_compared(const function_type& first,
 			   const function_type& second) const
   {
-    const environment* env = first.get_environment();
-    ABG_ASSERT(env);
-    env->priv_->fn_types_being_compared_.erase
+    const environment& env = first.get_environment();
+    env.priv_->fn_types_being_compared_.erase
       (std::make_pair(reinterpret_cast<uint64_t>(&first),
 		      reinterpret_cast<uint64_t>(&second)));
   }
@@ -1374,9 +1368,8 @@ struct function_type::priv
   comparison_started(const function_type& first,
 		     const function_type& second) const
   {
-    const environment* env = first.get_environment();
-    ABG_ASSERT(env);
-    return env->priv_->fn_types_being_compared_.count
+    const environment& env = first.get_environment();
+    return env.priv_->fn_types_being_compared_.count
       (std::make_pair(reinterpret_cast<uint64_t>(&first),
 		      reinterpret_cast<uint64_t>(&second)));
   }
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 5193934a..7735447b 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -28,70 +28,17 @@ ABG_BEGIN_EXPORT_DECLARATIONS
 #include "abg-interned-str.h"
 #include "abg-ir.h"
 #include "abg-corpus.h"
-#include "abg-corpus-priv.h"
 
 ABG_END_EXPORT_DECLARATIONS
 // </headers defining libabigail's API>
 
+#include "abg-corpus-priv.h"
 #include "abg-tools-utils.h"
 #include "abg-comp-filter.h"
 #include "abg-ir-priv.h"
 
 namespace
 {
-/// This internal type is a tree walker that walks the sub-tree of a
-/// type and sets the environment of the type (including its sub-type)
-/// to a new environment.
-class environment_setter : public abigail::ir::ir_node_visitor
-{
-  const abigail::ir::environment* env_;
-
-public:
-  environment_setter(const abigail::ir::environment* env)
-    : env_(env)
-  {}
-
-  /// This function is called on each sub-tree node that is a
-  /// declaration.  Note that it's also called on some types because
-  /// most types that have a declarations also inherit the type @ref
-  /// decl_base.
-  ///
-  /// @param d the declaration being visited.
-  bool
-  visit_begin(abigail::ir::decl_base* d)
-  {
-    if (const abigail::ir::environment* env = d->get_environment())
-      {
-	ABG_ASSERT(env == env_);
-	return false;
-      }
-    else
-      d->set_environment(env_);
-
-    return true;
-
-  }
-
-  /// This function is called on each sub-tree node that is a type.
-  ///
-  /// @param t the type being visited.
-  bool
-  visit_begin(abigail::ir::type_base* t)
-  {
-    if (abigail::ir::environment* env = t->get_environment())
-      {
-	ABG_ASSERT(env == env_);
-	return false;
-      }
-    else
-      {
-	ABG_ASSERT(!t->get_environment());
-	t->set_environment(env_);
-      }
-    return true;
-  }
-};
-
 /// This internal type is a tree walking that is used to set the
 /// qualified name of a tree of decls and types.  It used by the
 /// function update_qualified_name().
@@ -297,8 +244,8 @@ void
 push_composite_type_comparison_operands(const type_base& left,
 					const type_base& right)
 {
-  const environment * env = left.get_environment();
-  env->priv_->push_composite_type_comparison_operands(&left, &right);
+  const environment& env = left.get_environment();
+  env.priv_->push_composite_type_comparison_operands(&left, &right);
 }
 
 /// Pop a pair of operands from the stack of operands to the current
@@ -318,8 +265,8 @@ void
 pop_composite_type_comparison_operands(const type_base& left,
 				       const type_base& right)
 {
-  const environment * env = left.get_environment();
-  env->priv_->pop_composite_type_comparison_operands(&left, &right);
+  const environment& env = left.get_environment();
+  env.priv_->pop_composite_type_comparison_operands(&left, &right);
 }
 
 /// In the stack of the current types being compared (as part of type
@@ -381,9 +328,9 @@ pop_composite_type_comparison_operands(const type_base& left,
 bool
 mark_dependant_types_compared_until(const type_base &r)
 {
-  const environment * env = r.get_environment();
-  if (env->do_on_the_fly_canonicalization())
-    return env->priv_->mark_dependant_types_compared_until(&r);
+  const environment& env = r.get_environment();
+  if (env.do_on_the_fly_canonicalization())
+    return env.priv_->mark_dependant_types_compared_until(&r);
   return false;
 }
 
@@ -888,8 +835,8 @@ try_canonical_compare(const T *l, const T *r)
   // instructing us to compare them canonically, and the second time
   // with that boolean set to false, instructing us to compare them
   // structurally.
-  const environment *env = l->get_environment();
-  if (env->priv_->use_canonical_type_comparison_)
+  const environment&env = l->get_environment();
+  if (env.priv_->use_canonical_type_comparison_)
     {
       if (const type_base *lc = l->get_naked_canonical_type())
 	if (const type_base *rc = r->get_naked_canonical_type())
@@ -1073,8 +1020,8 @@ return_comparison_result(T& l, T& r, bool value,
 
   unmark_types_as_being_compared(l, r);
 
-  const environment* env = l.get_environment();
-  if (env->do_on_the_fly_canonicalization())
+  const environment& env = l.get_environment();
+  if (env.do_on_the_fly_canonicalization())
     // We are instructed to perform the "canonical type propagation"
     // optimization, making 'r' to possibly get the canonical type of
     // 'l' if it has one.  This mostly means that we are currently
@@ -1083,17 +1030,17 @@ return_comparison_result(T& l, T& r, bool value,
     {
       if (value == true
 	  && (is_type(&r)->priv_->depends_on_recursive_type()
-	      || env->priv_->is_recursive_type(&r))
+	      || env.priv_->is_recursive_type(&r))
 	  && is_type(&r)->priv_->canonical_type_propagated()
 	  && !is_type(&r)->priv_->propagated_canonical_type_confirmed()
-	  && !env->priv_->right_type_comp_operands_.empty())
+	  && !env.priv_->right_type_comp_operands_.empty())
 	{
 	  // Track the object 'r' for which the propagated canonical
 	  // type might be re-initialized if the current comparison
 	  // eventually fails.
-	  env->priv_->add_to_types_with_non_confirmed_propagated_ct(is_type(&r));
+	  env.priv_->add_to_types_with_non_confirmed_propagated_ct(is_type(&r));
 	}
-      else if (value == true && env->priv_->right_type_comp_operands_.empty())
+      else if (value == true && env.priv_->right_type_comp_operands_.empty())
 	{
 	  // The type provided in the 'r' argument is the type that is
 	  // being canonicalized; 'r' is not a mere subtype being
@@ -1102,16 +1049,16 @@ return_comparison_result(T& l, T& r, bool value,
 	  // confirm the "canonical type propagation" of all the
 	  // sub-types that were compared during the comparison of
 	  // 'r'.
-	  env->priv_->confirm_ct_propagation(&r);
+	  env.priv_->confirm_ct_propagation(&r);
 	}
       else if (value == false)
 	{
 	  // The comparison of the current sub-type failed.  So all
 	  // the types in
-	  // env->prix_->types_with_non_confirmed_propagated_ct_
+	  // env.prix_->types_with_non_confirmed_propagated_ct_
 	  // should see their tentatively propagated canonical type
 	  // cancelled.
-	  env->priv_->cancel_ct_propagation(&r);
+	  env.priv_->cancel_ct_propagation(&r);
 	}
     }
 
@@ -1123,13 +1070,13 @@ return_comparison_result(T& l, T& r, bool value,
   // propagation can now see their tentative canonical type be
   // confirmed for real.
   if (value == true
-      && env->priv_->right_type_comp_operands_.empty()
-      && !env->priv_->types_with_non_confirmed_propagated_ct_.empty())
+      && env.priv_->right_type_comp_operands_.empty()
+      && !env.priv_->types_with_non_confirmed_propagated_ct_.empty())
     // So the comparison is completely done and there are some
     // types for which their propagated canonical type is sitll
     // considered not confirmed.  As the comparison did yield true, we
     // shall now confirm the propagation for all those types.
-    env->priv_->confirm_ct_propagation();
+    env.priv_->confirm_ct_propagation();
 
   ABG_RETURN(value);
 }
@@ -1188,7 +1135,7 @@ type_maps::get_types_sorted_by_name() const
 ///
 /// @param address_size the size of addresses in the translation unit,
 /// in bits.
-translation_unit::translation_unit(const environment*	env,
+translation_unit::translation_unit(const environment&	env,
 				   const std::string&	path,
 				   char		address_size)
   : priv_(new priv(env))
@@ -1220,10 +1167,6 @@ translation_unit::get_global_scope()
     {
       priv_->global_scope_.reset
 	(new global_scope(const_cast<translation_unit*>(this)));
-      // The global scope must be out of the same environment as its
-      // translation unit.
-      priv_->global_scope_->
-	set_environment(const_cast<environment*>(get_environment()));
       priv_->global_scope_->set_translation_unit
 	(const_cast<translation_unit*>(this));
     }
@@ -1256,24 +1199,10 @@ translation_unit::get_live_fn_types() const
 /// Getter of the environment of the current @ref translation_unit.
 ///
 /// @return the translation unit of the current translation unit.
-const environment*
+const environment&
 translation_unit::get_environment() const
 {return priv_->env_;}
 
-/// Getter of the environment of the current @ref translation_unit.
-///
-/// @return the translation unit of the current translation unit.
-environment*
-translation_unit::get_environment()
-{return const_cast<environment*>(priv_->env_);}
-
-/// Setter of the environment of the current @ref translation_unit.
-///
-/// @param env the environment.
-void
-translation_unit::set_environment(const environment* env)
-{priv_->env_ = env;}
-
 /// Getter of the language of the source code of the translation unit.
 ///
 /// @return the language of the source code.
@@ -1496,8 +1425,7 @@ translation_unit::operator!=(const translation_unit& o) const
 void
 translation_unit::bind_function_type_life_time(function_type_sptr ftype) const
 {
-  const environment* env = get_environment();
-  ABG_ASSERT(env);
+  const environment& env = get_environment();
 
   const_cast<translation_unit*>(this)->priv_->live_fn_types_.push_back(ftype);
 
@@ -1507,10 +1435,10 @@ translation_unit::bind_function_type_life_time(function_type_sptr ftype) const
 
   // The function type must be out of the same environment as its
   // translation unit.
-  if (const environment* e = ftype->get_environment())
-    ABG_ASSERT(env == e);
-  else
-    ftype->set_environment(const_cast<environment*>(env));
+  {
+    const environment& e = ftype->get_environment();
+    ABG_ASSERT(&env == &e);
+  }
 
   if (const translation_unit* existing_tu = ftype->get_translation_unit())
     ABG_ASSERT(existing_tu == this);
@@ -1749,7 +1677,7 @@ operator!=(const translation_unit_sptr& l, const translation_unit_sptr& r)
 // <elf_symbol stuff>
 struct elf_symbol::priv
 {
-  const environment*	env_;
+  const environment&	env_;
   size_t		index_;
   size_t		size_;
   string		name_;
@@ -1796,8 +1724,8 @@ struct elf_symbol::priv
   elf_symbol_wptr	next_common_instance_;
   string		id_string_;
 
-  priv()
-    : env_(),
+  priv(const environment& e)
+    : env_(e),
       index_(),
       size_(),
       type_(elf_symbol::NOTYPE_TYPE),
@@ -1811,7 +1739,7 @@ struct elf_symbol::priv
       is_suppressed_(false)
   {}
 
-  priv(const environment*	  e,
+  priv(const environment&	  e,
        size_t			  i,
        size_t			  s,
        const string&		  n,
@@ -1845,16 +1773,6 @@ struct elf_symbol::priv
   }
 }; // end struct elf_symbol::priv
 
-/// Default constructor of the @ref elf_symbol type.
-///
-/// Note that this constructor is private, so client code cannot use
-/// it to create instances of @ref elf_symbol.  Rather, client code
-/// should use the @ref elf_symbol::create() function to create
-/// instances of @ref elf_symbol instead.
-elf_symbol::elf_symbol()
-  : priv_(new priv)
-{}
-
 /// Constructor of the @ref elf_symbol type.
 ///
 /// Note that this constructor is private, so client code cannot use
@@ -1885,7 +1803,7 @@ elf_symbol::elf_symbol()
 /// @param crc the CRC (modversions) value of Linux Kernel symbols
 ///
 /// @param ns the namespace of Linux Kernel symbols, if any
-elf_symbol::elf_symbol(const environment* e,
+elf_symbol::elf_symbol(const environment& e,
 		       size_t		  i,
 		       size_t		  s,
 		       const string&	  n,
@@ -1915,20 +1833,6 @@ elf_symbol::elf_symbol(const environment* e,
 		   is_suppressed))
 {}
 
-/// Factory of instances of @ref elf_symbol.
-///
-/// This is the function to use to create instances of @ref elf_symbol.
-///
-/// @return a (smart) pointer to a newly created instance of @ref
-/// elf_symbol.
-elf_symbol_sptr
-elf_symbol::create()
-{
-  elf_symbol_sptr e(new elf_symbol());
-  e->priv_->main_symbol_ = e;
-  return e;
-}
-
 /// Factory of instances of @ref elf_symbol.
 ///
 /// This is the function to use to create instances of @ref elf_symbol.
@@ -1960,7 +1864,7 @@ elf_symbol::create()
 /// @return a (smart) pointer to a newly created instance of @ref
 /// elf_symbol.
 elf_symbol_sptr
-elf_symbol::create(const environment* e,
+elf_symbol::create(const environment& e,
 		   size_t	      i,
 		   size_t	      s,
 		   const string&      n,
@@ -2015,19 +1919,10 @@ textually_equals(const elf_symbol&l,
 /// elf_symbol.
 ///
 /// @return the enviroment used by the current instance of @ref elf_symbol.
-const environment*
+const environment&
 elf_symbol::get_environment() const
 {return priv_->env_;}
 
-/// Setter of the environment used by the current instance of @ref
-/// elf_symbol.
-///
-/// @param The new enviroment used by the current instance of @ref
-/// elf_symbol.
-void
-elf_symbol::set_environment(const environment* e) const
-{priv_->env_ = e;}
-
 /// Getter for the index
 ///
 /// @return the index of the symbol.
@@ -3593,7 +3488,7 @@ const type_base_sptr&
 environment::get_void_type() const
 {
   if (!priv_->void_type_)
-    priv_->void_type_.reset(new type_decl(const_cast<environment*>(this),
+    priv_->void_type_.reset(new type_decl(*this,
 					  intern("void"),
 					  0, 0, location()));
   return priv_->void_type_;
@@ -3609,7 +3504,7 @@ environment::get_variadic_parameter_type() const
 {
   if (!priv_->variadic_marker_type_)
     priv_->variadic_marker_type_.
-      reset(new type_decl(const_cast<environment*>(this),
+      reset(new type_decl(*this,
 			  intern("variadic parameter type"),
 			  0, 0, location()));
   return priv_->variadic_marker_type_;
@@ -4064,7 +3959,7 @@ struct type_or_decl_base::priv
   // hotspots, due to their use of dynamic_cast.
   void*			type_or_decl_ptr_;
   bool				hashing_started_;
-  const environment*		env_;
+  const environment&		env_;
   translation_unit*		translation_unit_;
   // The location of an artifact as seen from its input by the
   // artifact reader.  This might be different from the source
@@ -4082,7 +3977,7 @@ struct type_or_decl_base::priv
   ///
   /// @param k the identifier of the runtime type of the current
   /// instance of ABI artifact.
-  priv(const environment* e = 0,
+  priv(const environment& e,
        enum type_or_decl_kind k = ABSTRACT_TYPE_OR_DECL)
     : kind_(k),
       rtti_(),
@@ -4142,26 +4037,17 @@ operator&=(type_or_decl_base::type_or_decl_kind& l,
   return l;
 }
 
-/// Default constructor of @ref type_or_decl_base.
-type_or_decl_base::type_or_decl_base()
-  :priv_(new priv)
-{}
-
 /// Constructor of @ref type_or_decl_base.
 ///
 /// @param the environment the current ABI artifact is constructed
 /// from.
 ///
 /// @param k the runtime identifier bitmap of the type being built.
-type_or_decl_base::type_or_decl_base(const environment* e,
+type_or_decl_base::type_or_decl_base(const environment& e,
 				     enum type_or_decl_kind k)
   :priv_(new priv(e, k))
 {}
 
-/// Copy constructor of @ref type_or_decl_base.
-type_or_decl_base::type_or_decl_base(const type_or_decl_base& o)
-{*priv_ = *o.priv_;}
-
 /// The destructor of the @ref type_or_decl_base type.
 type_or_decl_base::~type_or_decl_base()
 {}
@@ -4280,22 +4166,10 @@ void
 type_or_decl_base::hashing_started(bool b) const
 {priv_->hashing_started_ = b;}
 
-/// Setter of the environment of the current ABI artifact.
-///
-/// This just sets the environment artifact of the current ABI
-/// artifact, not on its sub-trees.  If you want to set the
-/// environment of an ABI artifact including its sub-tree, use the
-/// abigail::ir::set_environment_for_artifact() function.
-///
-/// @param env the new environment.
-void
-type_or_decl_base::set_environment(const environment* env)
-{priv_->env_ = env;}
-
 /// Getter of the environment of the current ABI artifact.
 ///
 /// @return the environment of the artifact.
-const environment*
+const environment&
 type_or_decl_base::get_environment() const
 {return priv_->env_;}
 
@@ -4345,13 +4219,6 @@ type_or_decl_base::has_artificial_location() const
 	  && priv_->artificial_location_.get_is_artificial());
 }
 
-/// Getter of the environment of the current ABI artifact.
-///
-/// @return the environment of the artifact.
-environment*
-type_or_decl_base::get_environment()
-{return const_cast<environment*>(priv_->env_);}
-
 /// Get the @ref corpus this ABI artifact belongs to.
 ///
 /// @return the corpus this ABI artifact belongs to, or nil if it
@@ -4399,19 +4266,6 @@ const translation_unit*
 type_or_decl_base::get_translation_unit() const
 {return const_cast<type_or_decl_base*>(this)->get_translation_unit();}
 
-/// Assignment operator for @ref type_or_decl_base.
-///
-/// @param o the other instance to assign the current instance to.
-///
-/// return a reference to the assigned instance of @ref
-/// type_or_decl_base.
-type_or_decl_base&
-type_or_decl_base::operator=(const type_or_decl_base& o)
-{
-  *priv_ = *o.priv_;
-  return *this;
-}
-
 /// Traverse the the ABI artifact.
 ///
 /// @param v the visitor used to traverse the sub-tree nodes of the
@@ -4420,33 +4274,6 @@ bool
 type_or_decl_base::traverse(ir_node_visitor&)
 {return true;}
 
-/// Set the environment of a given ABI artifact, including recursively
-/// setting the environment on the sub-trees of the artifact.
-///
-/// @param artifact the artifact to set the environment for.
-///
-/// @param env the new environment.
-void
-set_environment_for_artifact(type_or_decl_base* artifact,
-			     const environment* env)
-{
-  ABG_ASSERT(artifact && env);
-
-  ::environment_setter s(env);
-  artifact->traverse(s);
-}
-
-/// Set the environment of a given ABI artifact, including recursively
-/// setting the environment on the sub-trees of the artifact.
-///
-/// @param artifact the artifact to set the environment for.
-///
-/// @param env the new environment.
-void
-set_environment_for_artifact(type_or_decl_base_sptr artifact,
-			     const environment* env)
-{set_environment_for_artifact(artifact.get(), env);}
-
 /// Non-member equality operator for the @type_or_decl_base type.
 ///
 /// @param lr the left-hand operand of the equality.
@@ -4590,13 +4417,13 @@ struct decl_base::priv
 /// @param linkage_name the linkage name of the declaration.
 ///
 /// @param vis the visibility of the declaration.
-decl_base::decl_base(const environment* e,
+decl_base::decl_base(const environment& e,
 		     const string&	name,
 		     const location&	locus,
 		     const string&	linkage_name,
 		     visibility	vis)
   : type_or_decl_base(e, ABSTRACT_DECL_BASE),
-    priv_(new priv(e->intern(name), e->intern(linkage_name), vis))
+    priv_(new priv(e.intern(name), e.intern(linkage_name), vis))
 {
   set_location(locus);
 }
@@ -4614,7 +4441,7 @@ decl_base::decl_base(const environment* e,
 /// constructed.
 ///
 /// @param vis the visibility of the declaration being constructed.
-decl_base::decl_base(const environment* e,
+decl_base::decl_base(const environment& e,
 		     const interned_string& name,
 		     const location& locus,
 		     const interned_string& linkage_name,
@@ -4632,26 +4459,13 @@ decl_base::decl_base(const environment* e,
 ///
 /// @param l the location where to find the declaration in the source
 /// code.
-decl_base::decl_base(const environment* e, const location& l)
+decl_base::decl_base(const environment& e, const location& l)
   : type_or_decl_base(e, ABSTRACT_DECL_BASE),
     priv_(new priv())
 {
   set_location(l);
 }
 
-decl_base::decl_base(const decl_base& d)
-  : type_or_decl_base(d)
-{
-  priv_->in_pub_sym_tab_ = d.priv_->in_pub_sym_tab_;
-  priv_->location_ = d.priv_->location_;
-  priv_->name_ = d.priv_->name_;
-  priv_->qualified_parent_name_ = d.priv_->qualified_parent_name_;
-  priv_->qualified_name_ = d.priv_->qualified_name_;
-  priv_->linkage_name_ = d.priv_->linkage_name_;
-  priv_->context_ = d.priv_->context_;
-  priv_->visibility_ = d.priv_->visibility_;
-}
-
 /// Getter for the qualified name.
 ///
 /// Unlike decl_base::get_qualified_name() this doesn't try to update
@@ -4831,7 +4645,7 @@ decl_base::set_location(const location& l)
 void
 decl_base::set_name(const string& n)
 {
-  priv_->name_ = get_environment()->intern(n);
+  priv_->name_ = get_environment().intern(n);
   priv_->is_anonymous_ = n.empty();
 }
 
@@ -4923,7 +4737,7 @@ decl_base::set_naming_typedef(const typedef_decl_sptr& t)
   priv_->naming_typedef_ = t;
   set_name(t->get_name());
   string qualified_name = build_qualified_name(get_scope(), t->get_name());
-  set_qualified_name(get_environment()->intern(qualified_name));
+  set_qualified_name(get_environment().intern(qualified_name));
   set_is_anonymous(false);
   // Now that the qualified type of the decl has changed, let's update
   // the qualified names of the member types of this decls.
@@ -4943,9 +4757,8 @@ decl_base::get_linkage_name() const
 void
 decl_base::set_linkage_name(const string& m)
 {
-  const environment* env = get_environment();
-  ABG_ASSERT(env);
-  priv_->linkage_name_ = env->intern(m);
+  const environment& env = get_environment();
+  priv_->linkage_name_ = env.intern(m);
 }
 
 /// Getter for the visibility of the decl.
@@ -5271,7 +5084,7 @@ get_decl_name_for_comparison(const decl_base &d)
       // other anymous types of the same kind.
       string r;
       r += get_generic_anonymous_internal_type_name(&d);
-      return d.get_environment()->intern(r);
+      return d.get_environment().intern(r);
     }
 
   interned_string n = (is_anonymous_or_typedef_named(d)
@@ -6722,8 +6535,7 @@ strip_typedef(const type_base_sptr type)
       return type;
     }
 
-  environment* env = type->get_environment();
-  ABG_ASSERT(env);
+  const environment& env = type->get_environment();
   type_base_sptr t = type;
 
   if (const typedef_decl_sptr ty = is_typedef(t))
@@ -6818,9 +6630,6 @@ strip_typedef(const type_base_sptr type)
 				ty->get_alignment_in_bits()));
     }
 
-  if (!t->get_environment())
-    set_environment_for_artifact(t, env);
-
   if (!t->get_translation_unit())
     t->set_translation_unit(type->get_translation_unit());
 
@@ -6852,12 +6661,12 @@ strip_useless_const_qualification(const qualified_type_def_sptr t)
 
   decl_base_sptr result = t;
   type_base_sptr u = t->get_underlying_type();
-  environment* env = t->get_environment();
+  const environment& env = t->get_environment();
 
   if ((t->get_cv_quals() & qualified_type_def::CV_CONST
        && (is_reference_type(u)))
       || (t->get_cv_quals() & qualified_type_def::CV_CONST
-	  && env->is_void_type(u))
+	  && env.is_void_type(u))
       || t->get_cv_quals() == qualified_type_def::CV_NONE)
     // Let's strip the const qualifier because a reference is always
     // 'const' and a const void doesn't make sense.  They will just
@@ -7696,7 +7505,7 @@ struct scope_decl::priv
 /// @param locus the source location where the scope_decl is defined.
 ///
 /// @param vis the visibility of the declaration.
-scope_decl::scope_decl(const environment* env,
+scope_decl::scope_decl(const environment& env,
 		       const string& name,
 		       const location& locus,
 		       visibility vis)
@@ -7712,7 +7521,7 @@ scope_decl::scope_decl(const environment* env,
 /// @param l the source location where the scope_decl is defined.
 ///
 /// @param vis the visibility of the declaration.
-scope_decl::scope_decl(const environment* env, location& l)
+scope_decl::scope_decl(const environment& env, location& l)
   : type_or_decl_base(env, ABSTRACT_SCOPE_DECL|ABSTRACT_DECL_BASE),
     decl_base(env, "", l),
     priv_(new priv)
@@ -7898,9 +7707,6 @@ scope_decl::add_member_decl(const decl_base_sptr& member)
 
   update_qualified_name(member);
 
-  if (const environment* env = get_environment())
-    set_environment_for_artifact(member, env);
-
   if (translation_unit* tu = get_translation_unit())
     {
       if (translation_unit* existing_tu = member->get_translation_unit())
@@ -8043,9 +7849,6 @@ scope_decl::insert_member_decl(decl_base_sptr member,
 
   update_qualified_name(member);
 
-  if (const environment* env = get_environment())
-    set_environment_for_artifact(member, env);
-
   if (translation_unit* tu = get_translation_unit())
     {
       if (translation_unit* existing_tu = member->get_translation_unit())
@@ -8714,18 +8517,18 @@ get_generic_anonymous_internal_type_name(const decl_base *d)
 {
   ABG_ASSERT(has_generic_anonymous_internal_type_name(d));
 
-  const environment *env = d->get_environment();
+  const environment&env = d->get_environment();
 
   interned_string result;
   if (is_class_type(d))
     result =
-      env->intern(tools_utils::get_anonymous_struct_internal_name_prefix());
+      env.intern(tools_utils::get_anonymous_struct_internal_name_prefix());
   else if (is_union_type(d))
     result =
-      env->intern(tools_utils::get_anonymous_union_internal_name_prefix());
+      env.intern(tools_utils::get_anonymous_union_internal_name_prefix());
   else if (is_enum_type(d))
     result =
-      env->intern(tools_utils::get_anonymous_enum_internal_name_prefix());
+      env.intern(tools_utils::get_anonymous_enum_internal_name_prefix());
   else
     ABG_ASSERT_NOT_REACHED;
 
@@ -8795,15 +8598,14 @@ get_type_name(const type_base* t, bool qualified, bool internal)
 	{
 	  string r;
 	  r += get_generic_anonymous_internal_type_name(d);
-	  return t->get_environment()->intern(r);
+	  return t->get_environment().intern(r);
 	}
 
       if (qualified)
 	return d->get_qualified_name(internal);
 
-      const environment *env = d->get_environment();
-      ABG_ASSERT(env);
-      return env->intern(get_internal_integral_type_name(t));
+      const environment&env = d->get_environment();
+      return env.intern(get_internal_integral_type_name(t));
     }
 
   if (qualified)
@@ -8844,13 +8646,11 @@ interned_string
 get_name_of_pointer_to_type(const type_base& pointed_to_type,
 			    bool qualified, bool internal)
 {
-  const environment* env = pointed_to_type.get_environment();
-  ABG_ASSERT(env);
-
+  const environment& env = pointed_to_type.get_environment();
   string tn = get_type_name(pointed_to_type, qualified, internal);
   tn =  tn + "*";
 
-  return env->intern(tn);
+  return env.intern(tn);
 }
 
 /// Get the name of the reference to a given type.
@@ -8869,8 +8669,7 @@ get_name_of_reference_to_type(const type_base& pointed_to_type,
 			      bool lvalue_reference,
 			      bool qualified, bool internal)
 {
-  const environment* env = pointed_to_type.get_environment();
-  ABG_ASSERT(env);
+  const environment& env = pointed_to_type.get_environment();
 
   string name = get_type_name(pointed_to_type, qualified, internal);
   if (lvalue_reference)
@@ -8878,7 +8677,7 @@ get_name_of_reference_to_type(const type_base& pointed_to_type,
   else
     name = name + "&&";
 
-  return env->intern(name);
+  return env.intern(name);
 }
 
 /// Get the name of a qualified type, given the underlying type and
@@ -8900,8 +8699,7 @@ get_name_of_qualified_type(const type_base_sptr& underlying_type,
 			   qualified_type_def::CV quals,
 			   bool qualified, bool internal)
 {
-  const environment* env = underlying_type->get_environment();
-  ABG_ASSERT(env);
+  const environment& env = underlying_type->get_environment();
 
   string quals_repr = get_string_representation_of_cv_quals(quals);
   string name = get_type_name(underlying_type, qualified, internal);
@@ -8931,7 +8729,7 @@ get_name_of_qualified_type(const type_base_sptr& underlying_type,
 	name = quals_repr + " " + name;
     }
 
-  return env->intern(name);
+  return env.intern(name);
 }
 
 /// Get the name of a given function type and return a copy of it.
@@ -8994,8 +8792,7 @@ get_function_type_name(const function_type& fn_type,
     internal
     ? peel_typedef_type(fn_type.get_return_type())
     : fn_type.get_return_type();
-  const environment* env = fn_type.get_environment();
-  ABG_ASSERT(env);
+  const environment& env = fn_type.get_environment();
 
   o <<  get_pretty_representation(return_type, internal);
 
@@ -9015,7 +8812,7 @@ get_function_type_name(const function_type& fn_type,
     }
   o <<")";
 
-  return env->intern(o.str());
+  return env.intern(o.str());
 }
 
 /// Get the name of a given method type and return a copy of it.
@@ -9076,8 +8873,7 @@ get_method_type_name(const method_type& fn_type,
     internal
     ? peel_typedef_type(fn_type.get_return_type())
     : fn_type.get_return_type();
-  const environment* env = fn_type.get_environment();
-  ABG_ASSERT(env);
+  const environment& env = fn_type.get_environment();
 
   if (return_type)
     o << return_type->get_cached_pretty_representation(internal);
@@ -9112,7 +8908,7 @@ get_method_type_name(const method_type& fn_type,
     }
   o <<")";
 
-  return env->intern(o.str());
+  return env.intern(o.str());
 }
 
 /// Build and return a copy of the pretty representation of an ABI
@@ -10572,7 +10368,7 @@ is_void_pointer_type(const type_base* type)
   // Look through typedefs in the pointed-to type as well.
   type_base * ty = t->get_pointed_to_type().get();
   ty = peel_qualified_or_typedef_type(ty);
-  if (ty->get_environment()->is_void_type(ty))
+  if (ty->get_environment().is_void_type(ty))
     return ty;
 
   return 0;
@@ -11198,10 +10994,9 @@ lookup_basic_type(const interned_string& type_name, const translation_unit& tu)
 type_decl_sptr
 lookup_basic_type(const string& type_name, const translation_unit& tu)
 {
-  const environment* env = tu.get_environment();
-  ABG_ASSERT(env);
+  const environment& env = tu.get_environment();
 
-  interned_string s = env->intern(type_name);
+  interned_string s = env.intern(type_name);
   return lookup_basic_type(s, tu);
 }
 
@@ -11221,10 +11016,8 @@ lookup_basic_type(const string& type_name, const translation_unit& tu)
 class_decl_sptr
 lookup_class_type(const string& fqn, const translation_unit& tu)
 {
-  const environment* env = tu.get_environment();
-  ABG_ASSERT(env);
-
-  interned_string s = env->intern(fqn);
+  const environment& env = tu.get_environment();
+  interned_string s = env.intern(fqn);
   return lookup_class_type(s, tu);
 }
 
@@ -11278,10 +11071,8 @@ lookup_union_type(const interned_string& type_name, const translation_unit& tu)
 union_decl_sptr
 lookup_union_type(const string& fqn, const translation_unit& tu)
 {
-  const environment* env = tu.get_environment();
-  ABG_ASSERT(env);
-
-  interned_string s = env->intern(fqn);
+  const environment& env = tu.get_environment();
+  interned_string s = env.intern(fqn);
   return lookup_union_type(s, tu);
 }
 
@@ -11312,10 +11103,8 @@ lookup_union_type_per_location(const interned_string &loc, const corpus& corp)
 union_decl_sptr
 lookup_union_type_per_location(const string& loc, const corpus& corp)
 {
-  const environment* env = corp.get_environment();
-  ABG_ASSERT(env);
-
-  return lookup_union_type_per_location(env->intern(loc), corp);
+  const environment& env = corp.get_environment();
+  return lookup_union_type_per_location(env.intern(loc), corp);
 }
 
 /// Lookup an enum type from a translation unit.
@@ -11350,10 +11139,8 @@ lookup_enum_type(const interned_string& type_name, const translation_unit& tu)
 enum_type_decl_sptr
 lookup_enum_type(const string& type_name, const translation_unit& tu)
 {
-  const environment* env = tu.get_environment();
-  ABG_ASSERT(env);
-
-  interned_string s = env->intern(type_name);
+  const environment& env = tu.get_environment();
+  interned_string s = env.intern(type_name);
   return lookup_enum_type(s, tu);
 }
 
@@ -11392,10 +11179,8 @@ lookup_typedef_type(const interned_string& type_name,
 typedef_decl_sptr
 lookup_typedef_type(const string& type_name, const translation_unit& tu)
 {
-  const environment* env = tu.get_environment();
-  ABG_ASSERT(env);
-
-  interned_string s = env->intern(type_name);
+  const environment& env = tu.get_environment();
+  interned_string s = env.intern(type_name);
   return lookup_typedef_type(s, tu);
 }
 
@@ -11481,10 +11266,8 @@ lookup_pointer_type(const interned_string& type_name,
 pointer_type_def_sptr
 lookup_pointer_type(const string& type_name, const translation_unit& tu)
 {
-  const environment* env = tu.get_environment();
-  ABG_ASSERT(env);
-
-  interned_string s = env->intern(type_name);
+  const environment& env = tu.get_environment();
+  interned_string s = env.intern(type_name);
   return lookup_pointer_type(s, tu);
 }
 
@@ -11666,9 +11449,8 @@ lookup_type(const interned_string& fqn,
 type_base_sptr
 lookup_type(const string& fqn, const translation_unit& tu)
 {
-  const environment *env = tu.get_environment();
-  ABG_ASSERT(env);
-  interned_string ifqn = env->intern(fqn);
+  const environment&env = tu.get_environment();
+  interned_string ifqn = env.intern(fqn);
   return lookup_type(ifqn, tu);
 }
 
@@ -12450,10 +12232,8 @@ lookup_basic_type_per_location(const interned_string &loc,
 type_decl_sptr
 lookup_basic_type_per_location(const string &loc, const corpus &corp)
 {
-  const environment* env = corp.get_environment();
-  ABG_ASSERT(env);
-
-  return lookup_basic_type_per_location(env->intern(loc), corp);
+  const environment& env = corp.get_environment();
+  return lookup_basic_type_per_location(env.intern(loc), corp);
 }
 
 /// Look into a given corpus to find a basic type which has a given
@@ -12471,7 +12251,7 @@ lookup_basic_type_per_location(const string &loc, const corpus &corp)
 type_decl_sptr
 lookup_basic_type(const string& qualified_name, const corpus& corp)
 {
-  return lookup_basic_type(corp.get_environment()->intern(qualified_name),
+  return lookup_basic_type(corp.get_environment().intern(qualified_name),
 			   corp);
 }
 
@@ -12508,7 +12288,7 @@ lookup_class_type(const class_decl& t, const corpus& corp)
 class_decl_sptr
 lookup_class_type(const string& qualified_name, const corpus& corp)
 {
-  interned_string s = corp.get_environment()->intern(qualified_name);
+  interned_string s = corp.get_environment().intern(qualified_name);
   return lookup_class_type(s, corp);
 }
 
@@ -12595,7 +12375,7 @@ lookup_decl_only_class_types(const interned_string& qualified_name,
 const type_base_wptrs_type*
 lookup_class_types(const string& qualified_name, const corpus& corp)
 {
-  interned_string s = corp.get_environment()->intern(qualified_name);
+  interned_string s = corp.get_environment().intern(qualified_name);
   return lookup_class_types(s, corp);
 }
 
@@ -12627,10 +12407,8 @@ lookup_class_type_per_location(const interned_string& loc,
 class_decl_sptr
 lookup_class_type_per_location(const string &loc, const corpus &corp)
 {
-  const environment* env = corp.get_environment();
-  ABG_ASSERT(env);
-
-  return lookup_class_type_per_location(env->intern(loc), corp);
+  const environment& env = corp.get_environment();
+  return lookup_class_type_per_location(env.intern(loc), corp);
 }
 
 /// Look into a given corpus to find a union type which has a given
@@ -12670,7 +12448,7 @@ lookup_union_type(const interned_string& type_name, const corpus& corp)
 union_decl_sptr
 lookup_union_type(const string& type_name, const corpus& corp)
 {
-  interned_string s = corp.get_environment()->intern(type_name);
+  interned_string s = corp.get_environment().intern(type_name);
   return lookup_union_type(s, corp);
 }
 
@@ -12708,7 +12486,7 @@ lookup_enum_type(const enum_type_decl& t, const corpus& corp)
 enum_type_decl_sptr
 lookup_enum_type(const string& qualified_name, const corpus& corp)
 {
-  interned_string s = corp.get_environment()->intern(qualified_name);
+  interned_string s = corp.get_environment().intern(qualified_name);
   return lookup_enum_type(s, corp);
 }
 
@@ -12764,7 +12542,7 @@ lookup_enum_types(const interned_string& qualified_name, const corpus& corp)
 const type_base_wptrs_type*
 lookup_enum_types(const string& qualified_name, const corpus& corp)
 {
-  interned_string s = corp.get_environment()->intern(qualified_name);
+  interned_string s = corp.get_environment().intern(qualified_name);
   return lookup_enum_types(s, corp);
 }
 
@@ -12795,10 +12573,8 @@ lookup_enum_type_per_location(const interned_string &loc, const corpus& corp)
 enum_type_decl_sptr
 lookup_enum_type_per_location(const string &loc, const corpus &corp)
 {
-  const environment* env = corp.get_environment();
-  ABG_ASSERT(env);
-
-  return lookup_enum_type_per_location(env->intern(loc), corp);
+  const environment& env = corp.get_environment();
+  return lookup_enum_type_per_location(env.intern(loc), corp);
 }
 
 /// Look into a given corpus to find a typedef type which has the
@@ -12835,7 +12611,7 @@ lookup_typedef_type(const typedef_decl& t, const corpus& corp)
 typedef_decl_sptr
 lookup_typedef_type(const string& qualified_name, const corpus& corp)
 {
-  interned_string s = corp.get_environment()->intern(qualified_name);
+  interned_string s = corp.get_environment().intern(qualified_name);
   return lookup_typedef_type(s, corp);
 }
 
@@ -12892,10 +12668,8 @@ lookup_typedef_type_per_location(const interned_string &loc, const corpus &corp)
 typedef_decl_sptr
 lookup_typedef_type_per_location(const string &loc, const corpus &corp)
 {
-  const environment* env = corp.get_environment();
-  ABG_ASSERT(env);
-
-  return lookup_typedef_type_per_location(env->intern(loc), corp);
+  const environment& env = corp.get_environment();
+  return lookup_typedef_type_per_location(env.intern(loc), corp);
 }
 
 /// Look into a corpus to find a class, union or typedef type which
@@ -13329,7 +13103,7 @@ maybe_update_types_lookup_map(const shared_ptr<TypeKind>& type,
   else if (location l = type->get_location())
     {
       string str = l.expand();
-      s = type->get_environment()->intern(str);
+      s = type->get_environment().intern(str);
     }
 
   istring_type_base_wptrs_map_type::iterator i = types_map.find(s);
@@ -13384,12 +13158,12 @@ maybe_update_types_lookup_map<class_decl>(const class_decl_sptr& class_type,
   if (use_type_name_as_key)
     {
       string qname = type->get_qualified_name();
-      s = type->get_environment()->intern(qname);
+      s = type->get_environment().intern(qname);
     }
   else if (location l = type->get_location())
     {
       string str = l.expand();
-      s = type->get_environment()->intern(str);
+      s = type->get_environment().intern(str);
     }
 
   bool result = false;
@@ -13988,7 +13762,6 @@ synthesize_type_from_translation_unit(const type_base_sptr& type,
 						p->get_size_in_bits(),
 						p->get_alignment_in_bits(),
 						p->get_location()));
-	      result->set_environment(pointed_to_type->get_environment());
 	    }
 	}
       else if (reference_type_def_sptr r = is_reference_type(type))
@@ -14002,7 +13775,6 @@ synthesize_type_from_translation_unit(const type_base_sptr& type,
 						  r->get_size_in_bits(),
 						  r->get_alignment_in_bits(),
 						  r->get_location()));
-	      result->set_environment(pointed_to_type->get_environment());
 	    }
 	}
       else if (function_type_sptr f = is_function_type(type))
@@ -14046,13 +13818,12 @@ synthesize_function_type_from_translation_unit(const function_type& fn_type,
 {
   function_type_sptr nil = function_type_sptr();
 
-  environment* env = tu.get_environment();
-  ABG_ASSERT(env);
+  const environment& env = tu.get_environment();
 
   type_base_sptr return_type = fn_type.get_return_type();
   type_base_sptr result_return_type;
-  if (!return_type || env->is_void_type(return_type))
-    result_return_type = env->get_void_type();
+  if (!return_type || env.is_void_type(return_type))
+    result_return_type = env.get_void_type();
   else
     result_return_type = synthesize_type_from_translation_unit(return_type, tu);
   if (!result_return_type)
@@ -14104,9 +13875,6 @@ synthesize_function_type_from_translation_unit(const function_type& fn_type,
 					   fn_type.get_alignment_in_bits()));
 
   tu.priv_->synthesized_types_.push_back(result_fn_type);
-  // The new synthesized type must be in the same environment as its
-  // translation unit.
-  result_fn_type->set_environment(tu.get_environment());
   tu.bind_function_type_life_time(result_fn_type);
 
   canonicalize(result_fn_type);
@@ -14149,17 +13917,14 @@ demangle_cplus_mangled_name(const string& mangled_name)
 ///
 /// @return either @p t if it is non-null, or the void type.
 type_base_sptr
-type_or_void(const type_base_sptr t, const environment* env)
+type_or_void(const type_base_sptr t, const environment& env)
 {
   type_base_sptr r;
 
   if (t)
     r = t;
   else
-    {
-      ABG_ASSERT(env);
-      r = type_base_sptr(env->get_void_type());
-    }
+    r = type_base_sptr(env.get_void_type());
 
   return r;
 }
@@ -14239,7 +14004,7 @@ types_defined_same_linux_kernel_corpus_public(const type_base& t1,
     {
       if (c1->get_is_declaration_only() != c2->get_is_declaration_only())
 	{
-	  if (c1->get_environment()->decl_only_class_equals_definition())
+	  if (c1->get_environment().decl_only_class_equals_definition())
 	    // At least one of classes/union is declaration-only.
 	    // Because we are in a context in which a declaration-only
 	    // class/union is equal to all definitions of that
@@ -14316,13 +14081,13 @@ compare_types_during_canonicalization(const type_base_sptr& canonical_type,
 				      const type_base_sptr& candidate_type)
 {
 #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
-  environment *env = canonical_type->get_environment();
-  if (env->debug_type_canonicalization_is_on())
+  const environment&env = canonical_type->get_environment();
+  if (env.debug_type_canonicalization_is_on())
     {
       bool canonical_equality = false, structural_equality = false;
-      env->priv_->use_canonical_type_comparison_ = false;
+      env.priv_->use_canonical_type_comparison_ = false;
       structural_equality = canonical_type == candidate_type;
-      env->priv_->use_canonical_type_comparison_ = true;
+      env.priv_->use_canonical_type_comparison_ = true;
       canonical_equality = canonical_type == candidate_type;
       if (canonical_equality != structural_equality)
 	{
@@ -14365,8 +14130,7 @@ type_base::get_canonical_type_for(type_base_sptr t)
   if (!t)
     return t;
 
-  environment* env = t->get_environment();
-  ABG_ASSERT(env);
+  environment& env = const_cast<environment&>(t->get_environment());
 
   if (is_non_canonicalized_type(t))
     // This type should not be canonicalized!
@@ -14377,7 +14141,7 @@ type_base::get_canonical_type_for(type_base_sptr t)
 
   // Look through decl-only types (classes, unions and enums)
   bool decl_only_class_equals_definition =
-    (odr_is_relevant(*t) || env->decl_only_class_equals_definition());
+    (odr_is_relevant(*t) || env.decl_only_class_equals_definition());
 
   class_or_union_sptr class_or_union = is_class_or_union_type(t);
 
@@ -14424,7 +14188,7 @@ type_base::get_canonical_type_for(type_base_sptr t)
   // type.
   type_base_sptr canonical_type_present_in_corpus;
   environment::canonical_types_map_type& types =
-    env->get_canonical_types_map();
+    env.get_canonical_types_map();
 
   type_base_sptr result;
   environment::canonical_types_map_type::iterator i = types.find(repr);
@@ -14465,20 +14229,20 @@ type_base::get_canonical_type_for(type_base_sptr t)
 	  // declaration-only struct S should be left alone and not
 	  // resolved to any of the two definitions of struct S.
 	  bool saved_decl_only_class_equals_definition =
-	    env->decl_only_class_equals_definition();
-	  env->do_on_the_fly_canonicalization(true);
+	    env.decl_only_class_equals_definition();
+	  env.do_on_the_fly_canonicalization(true);
 	  // Compare types by considering that decl-only classes don't
 	  // equal their definition.
-	  env->decl_only_class_equals_definition(false);
-	  env->priv_->allow_type_comparison_results_caching(true);
+	  env.decl_only_class_equals_definition(false);
+	  env.priv_->allow_type_comparison_results_caching(true);
 	  bool equal = (types_defined_same_linux_kernel_corpus_public(**it, *t)
 			|| compare_types_during_canonicalization(*it, t));
 	  // Restore the state of the on-the-fly-canonicalization and
 	  // the decl-only-class-being-equal-to-a-matching-definition
 	  // flags.
-	  env->priv_->allow_type_comparison_results_caching(false);
-	  env->do_on_the_fly_canonicalization(false);
-	  env->decl_only_class_equals_definition
+	  env.priv_->allow_type_comparison_results_caching(false);
+	  env.do_on_the_fly_canonicalization(false);
+	  env.decl_only_class_equals_definition
 	    (saved_decl_only_class_equals_definition);
 	  if (equal)
 	    {
@@ -14487,12 +14251,12 @@ type_base::get_canonical_type_for(type_base_sptr t)
 	    }
 	}
 #ifdef WITH_DEBUG_SELF_COMPARISON
-      if (env->self_comparison_debug_is_on())
+      if (env.self_comparison_debug_is_on())
 	{
 	  // So we are debugging the canonicalization process,
 	  // possibly via the use of 'abidw --debug-abidiff <binary>'.
 	  corpus_sptr corp1, corp2;
-	  env->get_self_comparison_debug_inputs(corp1, corp2);
+	  env.get_self_comparison_debug_inputs(corp1, corp2);
 	  if (corp1 && corp2 && t->get_corpus() == corp2.get())
 	    {
 	      // If 't' comes from the second corpus, then it *must*
@@ -14503,7 +14267,7 @@ type_base::get_canonical_type_for(type_base_sptr t)
 	      // have canonical types coming from the first corpus.
 	      if (result)
 		{
-		  if (!env->priv_->
+		  if (!env.priv_->
 		      check_canonical_type_from_abixml_during_self_comp(t,
 									result))
 		    // The canonical type of the type re-read from abixml
@@ -14521,7 +14285,7 @@ type_base::get_canonical_type_for(type_base_sptr t)
 	      else //!result
 		{
 		  uintptr_t ptr_val = reinterpret_cast<uintptr_t>(t.get());
-		  string type_id = env->get_type_id_from_pointer(ptr_val);
+		  string type_id = env.get_type_id_from_pointer(ptr_val);
 		  if (type_id.empty())
 		    type_id = "type-id-<not-found>";
 		  // We are in the case where 't' is different from all
@@ -14743,7 +14507,7 @@ decl_base::set_definition_of_declaration(const decl_base_sptr& d)
 /// @param s the size of the type, in bits.
 ///
 /// @param a the alignment of the type, in bits.
-type_base::type_base(const environment* e, size_t s, size_t a)
+type_base::type_base(const environment& e, size_t s, size_t a)
   : type_or_decl_base(e, ABSTRACT_TYPE_BASE|ABSTRACT_TYPE_BASE),
     priv_(new priv(s, a))
 {}
@@ -14796,7 +14560,7 @@ type_base::get_cached_pretty_representation(bool internal) const
       if (!get_naked_canonical_type() || priv_->internal_cached_repr_.empty())
 	{
 	  string r = ir::get_pretty_representation(this, internal);
-	  priv_->internal_cached_repr_ = get_environment()->intern(r);
+	  priv_->internal_cached_repr_ = get_environment().intern(r);
 	}
       return priv_->internal_cached_repr_;
     }
@@ -14804,7 +14568,7 @@ type_base::get_cached_pretty_representation(bool internal) const
   if (!get_naked_canonical_type() || priv_->cached_repr_.empty())
     {
       string r = ir::get_pretty_representation(this, internal);
-      priv_->cached_repr_ = get_environment()->intern(r);
+      priv_->cached_repr_ = get_environment().intern(r);
     }
 
   return priv_->cached_repr_;
@@ -15291,7 +15055,7 @@ integral_type::operator string() const
 /// @param linkage_name the linkage_name of the current type declaration.
 ///
 /// @param vis the visibility of the type declaration.
-type_decl::type_decl(const environment* env,
+type_decl::type_decl(const environment& env,
 		     const string&	name,
 		     size_t		size_in_bits,
 		     size_t		alignment_in_bits,
@@ -15476,8 +15240,8 @@ type_decl::get_qualified_name(interned_string& qualified_name,
 const interned_string&
 type_decl::get_qualified_name(bool internal) const
 {
-  const environment* env = get_environment();
-  ABG_ASSERT(env);
+  const environment& env = get_environment();
+
 
   if (internal)
     if (is_integral_type(this))
@@ -15486,13 +15250,13 @@ type_decl::get_qualified_name(bool internal) const
 	  {
 	    if (decl_base::priv_->internal_qualified_name_.empty())
 	      decl_base::priv_->internal_qualified_name_ =
-		env->intern(get_internal_integral_type_name(this));
+		env.intern(get_internal_integral_type_name(this));
 	    return decl_base::priv_->internal_qualified_name_;
 	  }
 	else
 	  {
 	    decl_base::priv_->temporary_internal_qualified_name_ =
-	      env->intern(get_internal_integral_type_name(this));
+	      env.intern(get_internal_integral_type_name(this));
 	    return decl_base::priv_->temporary_internal_qualified_name_;
 	  }
       }
@@ -15569,7 +15333,7 @@ type_decl::~type_decl()
 /// @param locus the source location where the type is defined.
 ///
 /// @param vis the visibility of the type.
-scope_type_decl::scope_type_decl(const environment*	env,
+scope_type_decl::scope_type_decl(const environment&	env,
 				 const string&		name,
 				 size_t		size_in_bits,
 				 size_t		alignment_in_bits,
@@ -15706,7 +15470,7 @@ scope_type_decl::~scope_type_decl()
 /// @param locus the source location where the namespace is defined.
 ///
 /// @param vis the visibility of the namespace.
-namespace_decl::namespace_decl(const environment*	env,
+namespace_decl::namespace_decl(const environment&	env,
 			       const string&		name,
 			       const location&		locus,
 			       visibility		vis)
@@ -15883,7 +15647,7 @@ qualified_type_def::build_name(bool fully_qualified, bool internal) const
     // especially during the construction of the type, while the
     // underlying type is not yet constructed.  In that case, let's do
     // like if the underlying type is the 'void' type.
-    t = get_environment()->get_void_type();
+    t = get_environment().get_void_type();
 
   return get_name_of_qualified_type(t, get_cv_quals(),
 				    fully_qualified,
@@ -15922,7 +15686,7 @@ qualified_type_def::qualified_type_def(type_base_sptr		type,
     priv_(new priv(quals, type))
 {
   runtime_type_instance(this);
-  interned_string name = type->get_environment()->intern(build_name(false));
+  interned_string name = type->get_environment().intern(build_name(false));
   set_name(name);
 }
 
@@ -15933,7 +15697,7 @@ qualified_type_def::qualified_type_def(type_base_sptr		type,
 /// @param quals a bitfield representing the const/volatile qualifiers
 ///
 /// @param locus the location of the qualified type definition
-qualified_type_def::qualified_type_def(environment* env,
+qualified_type_def::qualified_type_def(const environment& env,
 				       CV quals,
 				       const location& locus)
   : type_or_decl_base(env,
@@ -15948,7 +15712,7 @@ qualified_type_def::qualified_type_def(environment* env,
   runtime_type_instance(this);
   // We don't yet have an underlying type.  So for naming purpose,
   // let's temporarily pretend the underlying type is 'void'.
-  interned_string name = env->intern("void");
+  interned_string name = env.intern("void");
   set_name(name);
 }
 
@@ -16109,8 +15873,8 @@ qualified_type_def::get_qualified_name(interned_string& qualified_name,
 const interned_string&
 qualified_type_def::get_qualified_name(bool internal) const
 {
-  const environment* env = get_environment();
-  ABG_ASSERT(env);
+  const environment& env = get_environment();
+
 
   if (!get_canonical_type())
     {
@@ -16124,14 +15888,14 @@ qualified_type_def::get_qualified_name(bool internal) const
 	  // Lets compute it and return a reference to where it's
 	  // stored.
 	  priv_->temporary_internal_name_ =
-	      env->intern(build_name(true, /*internal=*/true));
+	      env.intern(build_name(true, /*internal=*/true));
 	  return priv_->temporary_internal_name_;
 	}
       else
 	{
 	  // We are asked to return a temporary non-internal name.
 	    set_temporary_qualified_name
-	      (env->intern(build_name(true, /*internal=*/false)));
+	      (env.intern(build_name(true, /*internal=*/false)));
 	  return peek_temporary_qualified_name();
 	}
     }
@@ -16143,7 +15907,7 @@ qualified_type_def::get_qualified_name(bool internal) const
 	{
 	  if (priv_->internal_name_.empty())
 	    priv_->internal_name_ =
-	      env->intern(build_name(/*qualified=*/true,
+	      env.intern(build_name(/*qualified=*/true,
 				     /*internal=*/true));
 	  return priv_->internal_name_;
 	}
@@ -16151,7 +15915,7 @@ qualified_type_def::get_qualified_name(bool internal) const
 	{
 	  if (peek_qualified_name().empty())
 	    set_qualified_name
-	      (env->intern(build_name(/*qualified=*/true,
+	      (env.intern(build_name(/*qualified=*/true,
 				      /*internal=*/false)));
 	  return peek_qualified_name();
 	}
@@ -16225,7 +15989,7 @@ qualified_type_def::set_underlying_type(const type_base_sptr& t)
   // Now we need to update other properties that depend on the new underlying type.
   set_size_in_bits(t->get_size_in_bits());
   set_alignment_in_bits(t->get_alignment_in_bits());
-  interned_string name = get_environment()->intern(build_name(false));
+  interned_string name = get_environment().intern(build_name(false));
   set_name(name);
   if (scope_decl* s = get_scope())
       {
@@ -16350,7 +16114,7 @@ struct pointer_type_def::priv
   interned_string temp_internal_qualified_name_;
 
   priv(const type_base_sptr& t)
-    : pointed_to_type_(type_or_void(t, 0)),
+    : pointed_to_type_(type_or_void(t, t->get_environment())),
       naked_pointed_to_type_(t.get())
   {}
 
@@ -16396,10 +16160,10 @@ pointer_type_def::pointer_type_def(const type_base_sptr&	pointed_to,
   try
     {
       ABG_ASSERT(pointed_to);
-      const environment* env = pointed_to->get_environment();
+      const environment& env = pointed_to->get_environment();
       decl_base_sptr pto = dynamic_pointer_cast<decl_base>(pointed_to);
       string name = (pto ? pto->get_name() : string("void")) + "*";
-      set_name(env->intern(name));
+      set_name(env.intern(name));
       if (pto)
 	set_visibility(pto->get_visibility());
     }
@@ -16416,7 +16180,7 @@ pointer_type_def::pointer_type_def(const type_base_sptr&	pointed_to,
 /// @param align_in_bits the alignment of the type, in bits.
 ///
 /// @param locus the source location where the type was defined.
-pointer_type_def::pointer_type_def(environment* env, size_t size_in_bits,
+pointer_type_def::pointer_type_def(const environment& env, size_t size_in_bits,
 				   size_t alignment_in_bits,
 				   const location& locus)
   : type_or_decl_base(env,
@@ -16429,7 +16193,7 @@ pointer_type_def::pointer_type_def(environment* env, size_t size_in_bits,
 {
   runtime_type_instance(this);
   string name = string("void") + "*";
-  set_name(env->intern(name));
+  set_name(env.intern(name));
 }
 
 /// Set the pointed-to type of the pointer.
@@ -16444,11 +16208,10 @@ pointer_type_def::set_pointed_to_type(const type_base_sptr& t)
 
   try
     {
-      const environment* env = t->get_environment();
-      ABG_ASSERT(get_environment() == env);
+      const environment& env = t->get_environment();
       decl_base_sptr pto = dynamic_pointer_cast<decl_base>(t);
       string name = (pto ? pto->get_name() : string("void")) + "*";
-      set_name(env->intern(name));
+      set_name(env.intern(name));
       if (pto)
 	set_visibility(pto->get_visibility());
     }
@@ -16763,11 +16526,12 @@ reference_type_def::reference_type_def(const type_base_sptr	pointed_to,
 
       if (!is_lvalue())
 	name += "&";
-      environment* env = pointed_to->get_environment();
-      ABG_ASSERT(env);
-      set_name(env->intern(name));
+      const environment& env = pointed_to->get_environment();
+      set_name(env.intern(name));
 
-      pointed_to_type_ = type_base_wptr(type_or_void(pointed_to, 0));
+      pointed_to_type_ =
+	type_base_wptr(type_or_void(pointed_to,
+				    pointed_to->get_environment()));
     }
   catch (...)
     {}
@@ -16790,7 +16554,7 @@ reference_type_def::reference_type_def(const type_base_sptr	pointed_to,
 /// @param align_in_bits the alignment of the type, in bits.
 ///
 /// @param locus the source location of the type.
-reference_type_def::reference_type_def(const environment* env, bool lvalue,
+reference_type_def::reference_type_def(const environment& env, bool lvalue,
 				       size_t size_in_bits,
 				       size_t alignment_in_bits,
 				       const location& locus)
@@ -16806,9 +16570,9 @@ reference_type_def::reference_type_def(const environment* env, bool lvalue,
   string name = "void&";
   if (!is_lvalue())
     name += "&";
-  ABG_ASSERT(env);
-  set_name(env->intern(name));
-  pointed_to_type_ = type_base_wptr(env->get_void_type());
+
+  set_name(env.intern(name));
+  pointed_to_type_ = type_base_wptr(env.get_void_type());
 }
 
 /// Setter of the pointed_to type of the current reference type.
@@ -16832,9 +16596,8 @@ reference_type_def::set_pointed_to_type(type_base_sptr& pointed_to_type)
       string name = string(pto->get_name()) + "&";
       if (!is_lvalue())
 	name += "&";
-      environment* env = pto->get_environment();
-      ABG_ASSERT(env && env == get_environment());
-      set_name(env->intern(name));
+      const environment& env = pto->get_environment();
+      set_name(env.intern(name));
     }
 }
 
@@ -17210,7 +16973,7 @@ struct array_type_def::subrange_type::priv
 /// @param underlying_type the underlying type of the subrange type.
 ///
 /// @param loc the source location where the type is defined.
-array_type_def::subrange_type::subrange_type(const environment* env,
+array_type_def::subrange_type::subrange_type(const environment& env,
 					     const string&	name,
 					     bound_value	lower_bound,
 					     bound_value	upper_bound,
@@ -17242,7 +17005,7 @@ array_type_def::subrange_type::subrange_type(const environment* env,
 /// @param loc the source location where the type is defined.
 ///
 /// @param l the language that generated this subrange.
-array_type_def::subrange_type::subrange_type(const environment* env,
+array_type_def::subrange_type::subrange_type(const environment& env,
 					     const string&	name,
 					     bound_value	lower_bound,
 					     bound_value	upper_bound,
@@ -17270,7 +17033,7 @@ array_type_def::subrange_type::subrange_type(const environment* env,
 /// @param loc the source location of the type.
 ///
 /// @param the language that generated this type.
-array_type_def::subrange_type::subrange_type(const environment* env,
+array_type_def::subrange_type::subrange_type(const environment& env,
 					     const string&	name,
 					     bound_value	upper_bound,
 					     const location&	loc,
@@ -17625,7 +17388,7 @@ array_type_def::array_type_def(const type_base_sptr			e_type,
 /// @param subs a vector of the array's subranges(dimensions)
 ///
 /// @param locus the source location of the array type definition.
-array_type_def::array_type_def(environment*				env,
+array_type_def::array_type_def(const environment&				env,
 			       const std::vector<subrange_sptr>&	subs,
 			       const location&				locus)
   : type_or_decl_base(env,
@@ -17655,9 +17418,6 @@ array_type_def::update_size()
 	{
 	  for (const auto &sub : get_subranges())
 	    s *= sub->get_length();
-
-	  const environment* env = e->get_environment();
-	  ABG_ASSERT(env);
 	  set_size_in_bits(s);
 	}
       set_alignment_in_bits(e->get_alignment_in_bits());
@@ -17900,7 +17660,7 @@ array_type_def::set_element_type(const type_base_sptr& element_type)
 {
   priv_->element_type_ = element_type;
   update_size();
-  set_name(get_environment()->intern(get_pretty_representation()));
+  set_name(get_environment().intern(get_pretty_representation()));
 }
 
 /// Append subranges from the vector @param subs to the current
@@ -17913,7 +17673,7 @@ array_type_def::append_subranges(const std::vector<subrange_sptr>& subs)
     priv_->subranges_.push_back(sub);
 
   update_size();
-  set_name(get_environment()->intern(get_pretty_representation()));
+  set_name(get_environment().intern(get_pretty_representation()));
 }
 
 /// @return true if one of the sub-ranges of the array is infinite, or
@@ -17964,8 +17724,8 @@ array_type_def::get_qualified_name(interned_string& qn, bool internal) const
 const interned_string&
 array_type_def::get_qualified_name(bool internal) const
 {
-  const environment* env = get_environment();
-  ABG_ASSERT(env);
+  const environment& env = get_environment();
+
 
   if (internal)
     {
@@ -17973,13 +17733,13 @@ array_type_def::get_qualified_name(bool internal) const
 	{
 	  if (priv_->internal_qualified_name_.empty())
 	    priv_->internal_qualified_name_ =
-	      env->intern(get_type_representation(*this, /*internal=*/true));
+	      env.intern(get_type_representation(*this, /*internal=*/true));
 	  return priv_->internal_qualified_name_;
 	}
       else
 	{
 	  priv_->temp_internal_qualified_name_ =
-	    env->intern(get_type_representation(*this, /*internal=*/true));
+	    env.intern(get_type_representation(*this, /*internal=*/true));
 	  return priv_->temp_internal_qualified_name_;
 	}
     }
@@ -17988,13 +17748,13 @@ array_type_def::get_qualified_name(bool internal) const
       if (get_canonical_type())
 	{
 	  if (decl_base::peek_qualified_name().empty())
-	    set_qualified_name(env->intern(get_type_representation
+	    set_qualified_name(env.intern(get_type_representation
 					   (*this, /*internal=*/false)));
 	  return decl_base::peek_qualified_name();
 	}
       else
 	{
-	  set_temporary_qualified_name(env->intern(get_type_representation
+	  set_temporary_qualified_name(env.intern(get_type_representation
 						   (*this,
 						    /*internal=*/false)));
 	  return decl_base::peek_temporary_qualified_name();
@@ -18229,8 +17989,8 @@ enum_has_non_name_change(const enum_type_decl& l,
     }
 
   enum_type_decl &local_r = const_cast<enum_type_decl&>(r);
-  interned_string qn_r = l.get_environment()->intern(r.get_qualified_name());
-  interned_string qn_l = l.get_environment()->intern(l.get_qualified_name());
+  interned_string qn_r = l.get_environment().intern(r.get_qualified_name());
+  interned_string qn_l = l.get_environment().intern(l.get_qualified_name());
   string n_l = l.get_name();
   string n_r = r.get_name();
   local_r.set_qualified_name(qn_l);
@@ -18576,10 +18336,9 @@ operator!=(const enum_type_decl_sptr& l, const enum_type_decl_sptr& r)
 /// enum_type_decl::enumerator.
 class enum_type_decl::enumerator::priv
 {
-  const environment*	env_;
-  interned_string	name_;
+  string		name_;
   int64_t		value_;
-  interned_string	qualified_name_;
+  string		qualified_name_;
   enum_type_decl*	enum_type_;
 
   friend class	enum_type_decl::enumerator;
@@ -18587,16 +18346,13 @@ class enum_type_decl::enumerator::priv
 public:
 
   priv()
-    : env_(),
-      enum_type_()
+    : enum_type_()
   {}
 
-  priv(const environment* env,
-       const string& name,
+  priv(const string& name,
        int64_t value,
        enum_type_decl* e = 0)
-    : env_(env),
-      name_(env ? env->intern(name) : interned_string()),
+    : name_(name),
       value_(value),
       enum_type_(e)
   {}
@@ -18609,7 +18365,6 @@ enum_type_decl::enumerator::enumerator()
 
 enum_type_decl::enumerator::~enumerator() = default;
 
-
 /// Constructor of the @ref enum_type_decl::enumerator type.
 ///
 /// @param env the environment we are operating from.
@@ -18617,18 +18372,16 @@ enum_type_decl::enumerator::~enumerator() = default;
 /// @param name the name of the enumerator.
 ///
 /// @param value the value of the enumerator.
-enum_type_decl::enumerator::enumerator(const environment* env,
-				       const string& name,
+enum_type_decl::enumerator::enumerator(const string& name,
 				       int64_t value)
-  : priv_(new priv(env, name, value))
+  : priv_(new priv(name, value))
 {}
 
 /// Copy constructor of the @ref enum_type_decl::enumerator type.
 ///
 /// @param other enumerator to copy.
 enum_type_decl::enumerator::enumerator(const enumerator& other)
-  : priv_(new priv(other.get_environment(),
-		   other.get_name(),
+  : priv_(new priv(other.get_name(),
 		   other.get_value(),
 		   other.get_enum_type()))
 {}
@@ -18639,12 +18392,12 @@ enum_type_decl::enumerator::enumerator(const enumerator& other)
 enum_type_decl::enumerator&
 enum_type_decl::enumerator::operator=(const enumerator& o)
 {
-  priv_->env_ = o.get_environment();
   priv_->name_ = o.get_name();
   priv_->value_ = o.get_value();
   priv_->enum_type_ = o.get_enum_type();
   return *this;
 }
+
 /// Equality operator
 ///
 /// @param other the enumerator to compare to the current
@@ -18669,19 +18422,12 @@ bool
 enum_type_decl::enumerator::operator!=(const enumerator& other) const
 {return !operator==(other);}
 
-/// Getter of the environment of this enumerator.
-///
-/// @return the environment of this enumerator.
-const environment*
-enum_type_decl::enumerator::get_environment() const
-{return priv_->env_;}
-
 /// Getter for the name of the current instance of
 /// enum_type_decl::enumerator.
 ///
 /// @return a reference to the name of the current instance of
 /// enum_type_decl::enumerator.
-const interned_string&
+const string&
 enum_type_decl::enumerator::get_name() const
 {return priv_->name_;}
 
@@ -18698,17 +18444,15 @@ enum_type_decl::enumerator::get_name() const
 ///
 /// @return the qualified name of the current instance of
 /// enum_type_decl::enumerator.
-const interned_string&
+const string&
 enum_type_decl::enumerator::get_qualified_name(bool internal) const
 {
   if (priv_->qualified_name_.empty())
     {
-      const environment* env = priv_->enum_type_->get_environment();
-      ABG_ASSERT(env);
       priv_->qualified_name_ =
-	env->intern(get_enum_type()->get_qualified_name(internal)
-		    + "::"
-		    + get_name());
+	get_enum_type()->get_qualified_name(internal)
+	+ "::"
+	+ get_name();
     }
   return priv_->qualified_name_;
 }
@@ -18718,11 +18462,7 @@ enum_type_decl::enumerator::get_qualified_name(bool internal) const
 /// @param n the new name.
 void
 enum_type_decl::enumerator::set_name(const string& n)
-{
-  const environment* env = get_environment();
-  ABG_ASSERT(env);
-  priv_->name_ = env->intern(n);
-}
+{priv_->name_ = n;}
 
 /// Getter for the value of @ref enum_type_decl::enumerator.
 ///
@@ -18810,7 +18550,7 @@ typedef_decl::typedef_decl(const string&		name,
 ///
 /// @param vis the visibility of the typedef type.
 typedef_decl::typedef_decl(const string& name,
-			   environment* env,
+			   const environment& env,
 			   const location& locus,
 			   const string& mangled_name,
 			   visibility vis)
@@ -19117,7 +18857,7 @@ var_decl::set_symbol(const elf_symbol_sptr& sym)
   priv_->symbol_ = sym;
   // The variable id cache that depends on the symbol must be
   // invalidated because the symbol changed.
-  priv_->id_ = get_environment()->intern("");
+  priv_->id_ = get_environment().intern("");
 }
 
 /// Gets the the underlying ELF symbol for the current variable,
@@ -19241,10 +18981,10 @@ equals(const var_decl& l, const var_decl& r, change_kind* k)
       // The variables have underlying elf symbols that are equal, so
       // now, let's compare the decl_base part of the variables w/o
       // considering their decl names.
-      const environment* env = l.get_environment();
+      const environment& env = l.get_environment();
       const interned_string n1 = l.get_qualified_name(), n2 = r.get_qualified_name();
-      const_cast<var_decl&>(l).set_qualified_name(env->intern(""));
-      const_cast<var_decl&>(r).set_qualified_name(env->intern(""));
+      const_cast<var_decl&>(l).set_qualified_name(env.intern(""));
+      const_cast<var_decl&>(r).set_qualified_name(env.intern(""));
       bool decl_bases_different = !l.decl_base::operator==(r);
       const_cast<var_decl&>(l).set_qualified_name(n1);
       const_cast<var_decl&>(r).set_qualified_name(n2);
@@ -19321,11 +19061,11 @@ var_decl::get_id() const
 	sym_str = s->get_id_string();
       else if (!get_linkage_name().empty())
 	sym_str = get_linkage_name();
-      const environment* env = get_type()->get_environment();
-      ABG_ASSERT(env);
-      priv_->id_ = env->intern(repr);
+
+      const environment& env = get_type()->get_environment();
+      priv_->id_ = env.intern(repr);
       if (!sym_str.empty())
-	priv_->id_ = env->intern(priv_->id_ + "{" + sym_str + "}");
+	priv_->id_ = env.intern(priv_->id_ + "{" + sym_str + "}");
     }
   return priv_->id_;
 }
@@ -19374,7 +19114,7 @@ var_decl::get_qualified_name(bool internal) const
     {
       // Display the anonymous data member in a way that makes sense.
       string r = get_pretty_representation(internal);
-      set_qualified_name(get_environment()->intern(r));
+      set_qualified_name(get_environment().intern(r));
     }
 
   return decl_base::get_qualified_name(internal);
@@ -19614,7 +19354,7 @@ function_type::function_type(type_base_sptr return_type,
 /// @param size_in_bits the size of this type, in bits.
 ///
 /// @param alignment_in_bits the alignment of this type, in bits.
-function_type::function_type(const environment* env,
+function_type::function_type(const environment& env,
 			     size_t		size_in_bits,
 			     size_t		alignment_in_bits)
   : type_or_decl_base(env, FUNCTION_TYPE | ABSTRACT_TYPE_BASE),
@@ -19772,7 +19512,7 @@ equals(const function_type& l,
     // comparison has been cached, let's just re-use it, rather than
     // comparing them all over again.
     bool cached_result = false;
-    if (l.get_environment()->priv_->is_type_comparison_cached(l, r,
+    if (l.get_environment().priv_->is_type_comparison_cached(l, r,
 							      cached_result))
       return cached_result;
   }
@@ -19914,7 +19654,7 @@ equals(const function_type& l,
   // perform this caching also on the earlier return points of this
   // function.  That would basically mean to redefine the RETURN macro
   // to make it perform this caching for us.
-  l.get_environment()->priv_->cache_type_comparison_result(l, r, result);
+  l.get_environment().priv_->cache_type_comparison_result(l, r, result);
 
   RETURN(result);
 #undef RETURN
@@ -20186,7 +19926,7 @@ method_type::method_type(type_base_sptr return_type,
 /// @param size_in_bits the size of the type, expressed in bits.
 ///
 /// @param alignment_in_bits the alignment of the type, expressed in bits
-method_type::method_type(const environment*	env,
+method_type::method_type(const environment&	env,
 			 size_t		size_in_bits,
 			 size_t		alignment_in_bits)
   : type_or_decl_base(env, METHOD_TYPE | ABSTRACT_TYPE_BASE | FUNCTION_TYPE),
@@ -20493,7 +20233,7 @@ function_decl::get_pretty_representation_of_declarator (bool internal) const
       if (parm.get() != first_parm.get())
 	result += ", ";
       if (parm->get_variadic_marker()
-	  || get_environment()->is_variadic_parameter_type(parm->get_type()))
+	  || get_environment().is_variadic_parameter_type(parm->get_type()))
 	result += "...";
       else
 	{
@@ -20581,7 +20321,7 @@ function_decl::set_symbol(const elf_symbol_sptr& sym)
   priv_->symbol_ = sym;
   // The function id cache that depends on the symbol must be
   // invalidated because the symbol changed.
-  priv_->id_ = get_environment()->intern("");
+  priv_->id_ = get_environment().intern("");
 }
 
 /// Gets the the underlying ELF symbol for the current variable,
@@ -20880,22 +20620,22 @@ function_decl::get_id() const
 {
   if (priv_->id_.empty())
     {
-      const environment* env = get_type()->get_environment();
+      const environment& env = get_type()->get_environment();
       if (elf_symbol_sptr s = get_symbol())
 	{
 	  if (s->has_aliases())
 	    // The symbol has several aliases, so let's use a scheme
 	    // that allows all aliased functions to have different
 	    // IDs.
-	    priv_->id_ = env->intern(get_name() + "/" + s->get_id_string());
+	    priv_->id_ = env.intern(get_name() + "/" + s->get_id_string());
 	  else
 	    // Let's use the full symbol name with its version as ID.
-	    priv_->id_ = env->intern(s->get_id_string());
+	    priv_->id_ = env.intern(s->get_id_string());
 	}
       else if (!get_linkage_name().empty())
-	priv_->id_= env->intern(get_linkage_name());
+	priv_->id_= env.intern(get_linkage_name());
       else
-	priv_->id_ = env->intern(get_pretty_representation());
+	priv_->id_ = env.intern(get_pretty_representation());
     }
   return priv_->id_;
 }
@@ -21069,19 +20809,18 @@ function_decl::parameter::get_type()const
 interned_string
 function_decl::parameter::get_type_name() const
 {
-  const environment* env = get_environment();
-  ABG_ASSERT(env);
+  const environment& env = get_environment();
 
   type_base_sptr t = get_type();
   string str;
-  if (get_variadic_marker() || env->is_variadic_parameter_type(t))
+  if (get_variadic_marker() || env.is_variadic_parameter_type(t))
     str = "...";
   else
     {
 	ABG_ASSERT(t);
 	str = abigail::ir::get_type_name(t);
     }
-  return env->intern(str);
+  return env.intern(str);
 }
 
 /// @return a copy of the pretty representation of the type of the
@@ -21092,7 +20831,7 @@ function_decl::parameter::get_type_pretty_representation() const
   type_base_sptr t = get_type();
   string str;
   if (get_variadic_marker()
-      || get_environment()->is_variadic_parameter_type(t))
+      || get_environment().is_variadic_parameter_type(t))
     str = "...";
   else
     {
@@ -21108,13 +20847,13 @@ function_decl::parameter::get_type_pretty_representation() const
 interned_string
 function_decl::parameter::get_name_id() const
 {
-  const environment* env = get_environment();
-  ABG_ASSERT(env);
+  const environment& env = get_environment();
+
 
   std::ostringstream o;
   o << "parameter-" << get_index();
 
-  return env->intern(o.str());
+  return env.intern(o.str());
 }
 
 unsigned
@@ -21302,14 +21041,13 @@ string
 function_decl::parameter::get_pretty_representation(bool internal,
 						    bool /*qualified_name*/) const
 {
-  const environment* env = get_environment();
-  ABG_ASSERT(env);
+  const environment& env = get_environment();
 
   string type_repr;
   type_base_sptr t = get_type();
   if (!t)
     type_repr = "void";
-  else if (env->is_variadic_parameter_type(t))
+  else if (env.is_variadic_parameter_type(t))
     type_repr = "...";
   else
     type_repr = ir::get_pretty_representation(t, internal);
@@ -21351,7 +21089,7 @@ function_decl::parameter::get_pretty_representation(bool internal,
 ///
 /// @param member_fns the vector of member functions of this instance
 /// of @ref class_or_union.
-class_or_union::class_or_union(const environment* env, const string& name,
+class_or_union::class_or_union(const environment& env, const string& name,
 			       size_t size_in_bits, size_t align_in_bits,
 			       const location& locus, visibility vis,
 			       member_types& mem_types,
@@ -21401,7 +21139,7 @@ class_or_union::class_or_union(const environment* env, const string& name,
 /// @param locus the source location of declaration point this class.
 ///
 /// @param vis the visibility of instances of @ref class_or_union.
-class_or_union::class_or_union(const environment* env, const string& name,
+class_or_union::class_or_union(const environment& env, const string& name,
 			       size_t size_in_bits, size_t align_in_bits,
 			       const location& locus, visibility vis)
   : type_or_decl_base(env,
@@ -21423,7 +21161,7 @@ class_or_union::class_or_union(const environment* env, const string& name,
 ///
 /// @param is_declaration_only a boolean saying whether the instance
 /// represents a declaration only, or not.
-class_or_union::class_or_union(const environment* env, const string& name,
+class_or_union::class_or_union(const environment& env, const string& name,
 			       bool is_declaration_only)
   : type_or_decl_base(env,
 		      ABSTRACT_TYPE_BASE
@@ -22127,7 +21865,7 @@ class_or_union::operator==(const class_or_union& other) const
 /// classes of interest are being compared.
 void
 dump_classes_being_compared(const type_or_decl_base& c)
-{c.get_environment()->priv_->dump_classes_being_compared();}
+{c.get_environment().priv_->dump_classes_being_compared();}
 
 /// Dumps a textual representation (to the standard error output) of
 /// the content of the set of function types being currently compared
@@ -22139,7 +21877,7 @@ dump_classes_being_compared(const type_or_decl_base& c)
 /// function types of interest are being compared.
 void
 dump_fn_types_being_compared(const type_or_decl_base& t)
-{t.get_environment()->priv_->dump_fn_types_being_compared();}
+{t.get_environment().priv_->dump_fn_types_being_compared();}
 
 /// Compares two instances of @ref class_or_union.
 ///
@@ -22193,7 +21931,7 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
 	    // change.
 	    return true;
 
-	  if ((l.get_environment()->decl_only_class_equals_definition()
+	  if ((l.get_environment().decl_only_class_equals_definition()
 	       || ((odr_is_relevant(l) && !def1)
 		   || (odr_is_relevant(r) && !def2)))
 	      && !is_anonymous_or_typedef_named(l)
@@ -22414,7 +22152,6 @@ copy_member_function(const class_or_union_sptr& t, const method_decl* method)
 					    old_type->get_is_const(),
 					    old_type->get_size_in_bits(),
 					    old_type->get_alignment_in_bits()));
-  new_type->set_environment(t->get_environment());
   keep_type_alive(new_type);
 
   method_decl_sptr
@@ -22553,18 +22290,17 @@ static bool
 maybe_propagate_canonical_type(const type_base& lhs_type,
 			       const type_base& rhs_type)
 {
+  const environment& env = lhs_type.get_environment();
 #if WITH_DEBUG_TYPE_CANONICALIZATION
-  if (const environment *env = lhs_type.get_environment())
-    if (!env->priv_->use_canonical_type_comparison_)
-      return false;
+  if (!env.priv_->use_canonical_type_comparison_)
+    return false;
 #endif
 
-  if (const environment *env = lhs_type.get_environment())
-    if (env->do_on_the_fly_canonicalization())
-      if (type_base_sptr canonical_type = lhs_type.get_canonical_type())
-	if (!rhs_type.get_canonical_type())
-	  if (env->priv_->propagate_ct(lhs_type, rhs_type))
-	    return true;
+  if (env.do_on_the_fly_canonicalization())
+    if (type_base_sptr canonical_type = lhs_type.get_canonical_type())
+      if (!rhs_type.get_canonical_type())
+	if (env.priv_->propagate_ct(lhs_type, rhs_type))
+	  return true;
   return false;
 }
 
@@ -22623,7 +22359,7 @@ struct class_decl::priv
 ///
 /// @param mbr_fns the vector of member functions of this instance of
 /// class_decl.
-class_decl::class_decl(const environment* env, const string& name,
+class_decl::class_decl(const environment& env, const string& name,
 		       size_t size_in_bits, size_t align_in_bits,
 		       bool is_struct, const location& locus,
 		       visibility vis, base_specs& bases,
@@ -22674,7 +22410,7 @@ class_decl::class_decl(const environment* env, const string& name,
 ///
 /// @param is_anonymous whether the newly created instance is
 /// anonymous.
-class_decl::class_decl(const environment* env, const string& name,
+class_decl::class_decl(const environment& env, const string& name,
 		       size_t size_in_bits, size_t align_in_bits,
 		       bool is_struct, const location& locus,
 		       visibility vis, base_specs& bases,
@@ -22720,7 +22456,7 @@ class_decl::class_decl(const environment* env, const string& name,
 /// @param locus the source location of declaration point this class.
 ///
 /// @param vis the visibility of instances of class_decl.
-class_decl::class_decl(const environment* env, const string& name,
+class_decl::class_decl(const environment& env, const string& name,
 		       size_t size_in_bits, size_t align_in_bits,
 		       bool is_struct, const location& locus,
 		       visibility vis)
@@ -22757,7 +22493,7 @@ class_decl::class_decl(const environment* env, const string& name,
 ///
 /// @param is_anonymous whether the newly created instance is
 /// anonymous.
-class_decl:: class_decl(const environment* env, const string& name,
+class_decl:: class_decl(const environment& env, const string& name,
 			size_t size_in_bits, size_t align_in_bits,
 			bool is_struct, const location& locus,
 			visibility vis, bool is_anonymous)
@@ -22795,7 +22531,7 @@ class_decl:: class_decl(const environment* env, const string& name,
 ///
 /// @param is_declaration_only a boolean saying whether the instance
 /// represents a declaration only, or not.
-class_decl::class_decl(const environment* env, const string& name,
+class_decl::class_decl(const environment& env, const string& name,
 		       bool is_struct, bool is_declaration_only)
   : type_or_decl_base(env,
 		      CLASS_TYPE
@@ -22848,12 +22584,8 @@ class_decl::is_struct() const
 void
 class_decl::add_base_specifier(base_spec_sptr b)
 {
-  ABG_ASSERT(get_environment());
-  ABG_ASSERT(b->get_environment() == get_environment());
   priv_->bases_.push_back(b);
   priv_->bases_map_[b->get_base_class()->get_qualified_name()] = b;
-  if (const environment* env = get_environment())
-    b->set_environment(env);
 }
 
 /// Get the base specifiers for this class.
@@ -23755,12 +23487,12 @@ method_matches_at_least_one_in_vector(const method_decl_sptr& method,
 static bool
 maybe_cancel_propagated_canonical_type(const class_or_union& t)
 {
-  const environment* env = t.get_environment();
-  if (env && env->do_on_the_fly_canonicalization())
+  const environment& env = t.get_environment();
+  if (env.do_on_the_fly_canonicalization())
     if (is_type(&t)->priv_->canonical_type_propagated())
       {
 	is_type(&t)->priv_->clear_propagated_canonical_type();
-	env->priv_->remove_from_types_with_non_confirmed_propagated_ct(&t);
+	env.priv_->remove_from_types_with_non_confirmed_propagated_ct(&t);
 	return true;
       }
   return false;
@@ -23794,7 +23526,7 @@ equals(const class_decl& l, const class_decl& r, change_kind* k)
     // cached, let's just re-use it, rather than comparing them all
     // over again.
     bool result = false;
-    if (l.get_environment()->priv_->is_type_comparison_cached(l, r, result))
+    if (l.get_environment().priv_->is_type_comparison_cached(l, r, result))
       return result;
   }
 
@@ -23950,7 +23682,7 @@ equals(const class_decl& l, const class_decl& r, change_kind* k)
   // perform this caching also on the earlier return points of this
   // function.  That would basically mean to redefine the RETURN macro
   // to make it perform this caching for us.
-  l.get_environment()->priv_->cache_type_comparison_result(l, r, result);
+  l.get_environment().priv_->cache_type_comparison_result(l, r, result);
 
   RETURN(result);
 #undef RETURN
@@ -24591,7 +24323,7 @@ set_member_is_static(const decl_base_sptr& d, bool s)
 /// @param data_mbrs the data members of the union.
 ///
 /// @param member_fns the member functions of the union.
-union_decl::union_decl(const environment* env, const string& name,
+union_decl::union_decl(const environment& env, const string& name,
 		       size_t size_in_bits, const location& locus,
 		       visibility vis, member_types& mbr_types,
 		       data_members& data_mbrs, member_functions& member_fns)
@@ -24627,7 +24359,7 @@ union_decl::union_decl(const environment* env, const string& name,
 ///
 /// @param is_anonymous whether the newly created instance is
 /// anonymous.
-union_decl::union_decl(const environment* env, const string& name,
+union_decl::union_decl(const environment& env, const string& name,
 		       size_t size_in_bits, const location& locus,
 		       visibility vis, member_types& mbr_types,
 		       data_members& data_mbrs, member_functions& member_fns,
@@ -24665,7 +24397,7 @@ union_decl::union_decl(const environment* env, const string& name,
 /// @param locus the location of the type.
 ///
 /// @param vis the visibility of instances of @ref union_decl.
-union_decl::union_decl(const environment* env, const string& name,
+union_decl::union_decl(const environment& env, const string& name,
 		       size_t size_in_bits, const location& locus,
 		       visibility vis)
   : type_or_decl_base(env,
@@ -24696,7 +24428,7 @@ union_decl::union_decl(const environment* env, const string& name,
 ///
 /// @param is_anonymous whether the newly created instance is
 /// anonymous.
-union_decl::union_decl(const environment* env, const string& name,
+union_decl::union_decl(const environment& env, const string& name,
 		       size_t size_in_bits, const location& locus,
 		       visibility vis, bool is_anonymous)
   : type_or_decl_base(env,
@@ -24731,7 +24463,7 @@ union_decl::union_decl(const environment* env, const string& name,
 ///
 /// @param is_declaration_only a boolean saying whether the instance
 /// represents a declaration only, or not.
-union_decl::union_decl(const environment* env,
+union_decl::union_decl(const environment& env,
 		       const string& name,
 		       bool is_declaration_only)
   : type_or_decl_base(env,
@@ -24948,7 +24680,7 @@ equals(const union_decl& l, const union_decl& r, change_kind* k)
     // cached, let's just re-use it, rather than comparing them all
     // over again.
     bool result = false;
-    if (l.get_environment()->priv_->is_type_comparison_cached(l, r, result))
+    if (l.get_environment().priv_->is_type_comparison_cached(l, r, result))
       return result;
   }
 
@@ -24970,7 +24702,7 @@ equals(const union_decl& l, const union_decl& r, change_kind* k)
   // perform this caching also on the earlier return points of this
   // function.  That would basically mean to redefine the RETURN macro
   // to make it perform this caching for us.
-  l.get_environment()->priv_->cache_type_comparison_result(l, r, result);
+  l.get_environment().priv_->cache_type_comparison_result(l, r, result);
 
   RETURN(result);
 }
@@ -25076,7 +24808,7 @@ template_decl::get_template_parameters() const
 /// defined.
 ///
 /// @param vis the visibility of the template declaration.
-template_decl::template_decl(const environment* env,
+template_decl::template_decl(const environment& env,
 			     const string& name,
 			     const location& locus,
 			     visibility vis)
@@ -25556,7 +25288,7 @@ public:
 ///
 /// @param bind the binding of the declaration.  This is the binding
 /// the functions instantiated from this template are going to have.
-function_tdecl::function_tdecl(const environment*	env,
+function_tdecl::function_tdecl(const environment&	env,
 			       const location&		locus,
 			       visibility		vis,
 			       binding			bind)
@@ -25730,7 +25462,7 @@ public:
 ///
 /// @param vis the visibility of the instance of class instantiated
 /// from this template.
-class_tdecl::class_tdecl(const environment*	env,
+class_tdecl::class_tdecl(const environment&	env,
 			 const location&	locus,
 			 visibility		vis)
   : type_or_decl_base(env,
@@ -25976,9 +25708,8 @@ type_has_sub_type_changes(const type_base_sptr t_v1,
 void
 keep_type_alive(type_base_sptr t)
 {
-  environment* env = t->get_environment();
-  ABG_ASSERT(env);
-  env->priv_->extra_live_types_.push_back(t);
+  const environment& env = t->get_environment();
+  env.priv_->extra_live_types_.push_back(t);
 }
 
 /// Hash an ABI artifact that is either a type or a decl.
@@ -26107,10 +25838,10 @@ is_non_canonicalized_type(const type_base *t)
   if (!t)
     return true;
 
-  const environment* env = t->get_environment();
+  const environment& env = t->get_environment();
   return (is_declaration_only_class_or_union_type(t)
-	  || env->is_void_type(t)
-	  || env->is_variadic_parameter_type(t));
+	  || env.is_void_type(t)
+	  || env.is_variadic_parameter_type(t));
 }
 
 /// For a given type, return its exemplar type.
@@ -26984,15 +26715,15 @@ qualified_name_setter::do_update(abigail::ir::decl_base* d)
   else
     d->priv_->qualified_parent_name_ = abigail::interned_string();
 
-  abigail::environment* env = d->get_environment();
-  ABG_ASSERT(env);
+  const abigail::ir::environment& env = d->get_environment();
+
   if (!d->priv_->qualified_parent_name_.empty())
     {
       if (d->get_name().empty())
 	d->priv_->qualified_name_ = abigail::interned_string();
       else
 	d->priv_->qualified_name_ =
-	  env->intern(d->priv_->qualified_parent_name_ + "::" + d->get_name());
+	  env.intern(d->priv_->qualified_parent_name_ + "::" + d->get_name());
     }
 
   if (d->priv_->scoped_name_.empty())
@@ -27001,10 +26732,10 @@ qualified_name_setter::do_update(abigail::ir::decl_base* d)
 	  && !parent->get_is_anonymous()
 	  && !parent->get_name().empty())
 	d->priv_->scoped_name_ =
-	  env->intern(parent->get_name() + "::" + d->get_name());
+	  env.intern(parent->get_name() + "::" + d->get_name());
       else
 	d->priv_->scoped_name_ =
-	  env->intern(d->get_name());
+	  env.intern(d->get_name());
     }
 
   if (!is_scope_decl(d))
diff --git a/src/abg-reader.cc b/src/abg-reader.cc
index 4afa427a..dbc2f921 100644
--- a/src/abg-reader.cc
+++ b/src/abg-reader.cc
@@ -8,7 +8,7 @@
 /// This file contains the definitions of the entry points to
 /// de-serialize an instance of @ref abigail::translation_unit from an
 /// ABI Instrumentation file in libabigail native XML format.  This
-/// native XML format is named "abixml".
+/// native XML format is named "ABIXML".
 
 #include "config.h"
 #include <assert.h>
@@ -25,7 +25,7 @@
 #include "abg-suppression-priv.h"
 
 #include "abg-internal.h"
-#include "abg-tools-utils.h"
+#include "abg-symtab-reader.h"
 
 // <headers defining libabigail's API go under here>
 ABG_BEGIN_EXPORT_DECLARATIONS
@@ -33,7 +33,8 @@ ABG_BEGIN_EXPORT_DECLARATIONS
 #include "abg-libxml-utils.h"
 #include "abg-reader.h"
 #include "abg-corpus.h"
-#include "abg-symtab-reader.h"
+#include "abg-fe-iface.h"
+#include "abg-tools-utils.h"
 
 ABG_END_EXPORT_DECLARATIONS
 // </headers defining libabigail's API>
@@ -44,7 +45,7 @@ namespace abigail
 using xml::xml_char_sptr;
 
 /// The namespace for the native XML file format reader.
-namespace xml_reader
+namespace abixml_reader
 {
 using std::string;
 using std::deque;
@@ -54,6 +55,8 @@ using std::dynamic_pointer_cast;
 using std::vector;
 using std::istream;
 
+class reader;
+
 static bool	read_is_declaration_only(xmlNodePtr, bool&);
 static bool	read_is_artificial(xmlNodePtr, bool&);
 static bool	read_tracking_non_reachable_types(xmlNodePtr, bool&);
@@ -65,20 +68,44 @@ static bool	maybe_map_type_with_type_id(const type_base_sptr&,
 					    xmlNodePtr);
 static bool	maybe_map_type_with_type_id(const type_base_sptr&,
 					    const string&);
+
 #define MAYBE_MAP_TYPE_WITH_TYPE_ID(type, xml_node) \
   maybe_map_type_with_type_id(type, xml_node)
 #else
 #define MAYBE_MAP_TYPE_WITH_TYPE_ID(type, xml_node)
 #endif
-static void	maybe_set_naming_typedef(read_context&	ctxt, xmlNodePtr, const decl_base_sptr &);
-class read_context;
+static void	maybe_set_naming_typedef(reader& rdr,
+					 xmlNodePtr,
+					 const decl_base_sptr &);
+class reader;
+
+static int advance_cursor(reader& rdr);
+
+static void
+handle_version_attribute(xml::reader_sptr& reader, corpus& corp);
 
+static void
+walk_xml_node_to_map_type_ids(reader& rdr, xmlNodePtr node);
+
+static bool
+read_elf_needed_from_input(reader& rdr, vector<string>& needed);
+
+static bool
+read_symbol_db_from_input(reader&			rdr,
+			  string_elf_symbols_map_sptr&	fn_symdb,
+			  string_elf_symbols_map_sptr&	var_symdb);
+
+static translation_unit_sptr
+read_translation_unit_from_input(fe_iface& rdr);
+
+/// The ABIXML reader object.
+///
 /// This abstracts the context in which the current ABI
 /// instrumentation dump is being de-serialized.  It carries useful
 /// information needed during the de-serialization, but that does not
 /// make sense to be stored in the final resulting in-memory
 /// representation of ABI Corpus.
-class read_context
+class reader : public fe_iface
 {
 public:
 
@@ -102,15 +129,13 @@ public:
 
   typedef unordered_map<xmlNodePtr, decl_base_sptr> xml_node_decl_base_sptr_map;
 
-  friend vector<type_base_sptr>* get_types_from_type_id(read_context&,
+  friend vector<type_base_sptr>* get_types_from_type_id(reader&,
 							const string&);
 
   friend unordered_map<type_or_decl_base*, vector<type_or_decl_base*>>*
-	 get_artifact_used_by_relation_map(read_context& ctxt);
+	 get_artifact_used_by_relation_map(reader& rdr);
 
 private:
-  string						m_path;
-  environment*						m_env;
   unordered_map<string, vector<type_base_sptr> >	m_types_map;
   unordered_map<string, shared_ptr<function_tdecl> >	m_fn_tmpl_map;
   unordered_map<string, shared_ptr<class_tdecl> >	m_class_tmpl_map;
@@ -120,10 +145,6 @@ private:
   xml::reader_sptr					m_reader;
   xmlNodePtr						m_corp_node;
   deque<shared_ptr<decl_base> >			m_decls_stack;
-  corpus_sptr						m_corpus;
-  corpus_group_sptr					m_corpus_group;
-  corpus::exported_decls_builder*			m_exported_decls_builder;
-  suppr::suppressions_type				m_supprs;
   bool							m_tracking_non_reachable_types;
   bool							m_drop_undefined_syms;
 #ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
@@ -131,18 +152,18 @@ private:
 		vector<type_or_decl_base*>>		m_artifact_used_by_map;
 #endif
 
-  read_context();
+  reader();
 
 public:
-  read_context(xml::reader_sptr reader,
-	       environment*	env)
-    : m_env(env),
+  reader(xml::reader_sptr reader,
+	 environment&	env)
+    : fe_iface("", env),
       m_reader(reader),
       m_corp_node(),
-      m_exported_decls_builder(),
       m_tracking_non_reachable_types(),
       m_drop_undefined_syms()
-  {}
+  {
+  }
 
   /// Getter for the flag that tells us if we are tracking types that
   /// are not reachable from global functions and variables.
@@ -184,38 +205,33 @@ public:
   /// @return the path to the native xml abi file.
   const string&
   get_path() const
-  {return m_path;}
+  {return corpus_path();}
 
   /// Setter of the path to the ABI file.
   ///
   /// @param the new path to the native ABI file.
   void
   set_path(const string& s)
-  {m_path = s;}
+  {
+    corpus_path(s);
+  }
 
   /// Getter for the environment of this reader.
   ///
   /// @return the environment of this reader.
-  const environment*
-  get_environment() const
-  {return m_env;}
+  environment&
+  get_environment()
+  {return options().env;}
 
   /// Getter for the environment of this reader.
   ///
   /// @return the environment of this reader.
-  environment*
-  get_environment()
-  {return m_env;}
-
-  /// Setter for the environment of this reader.
-  ///
-  /// @param env the environment of this reader.
-  void
-  set_environment(environment* env)
-  {m_env = env;}
+  const environment&
+  get_environment() const
+  {return const_cast<reader*>(this)->get_environment();}
 
   xml::reader_sptr
-  get_reader() const
+  get_libxml_reader() const
   {return m_reader;}
 
   /// Getter of the current XML node in the corpus element sub-tree
@@ -749,39 +765,6 @@ public:
     return true;
   }
 
-  const corpus_sptr
-  get_corpus() const
-  {return m_corpus;}
-
-  corpus_sptr
-  get_corpus()
-  {return m_corpus;}
-
-  void
-  set_corpus(corpus_sptr c)
-  {m_corpus = c;}
-
-  /// Getter of the current corpus group.
-  ///
-  /// @return the current corpus group.n
-  const corpus_group_sptr&
-  get_corpus_group() const
-  {return m_corpus_group;}
-
-  /// Getter of the current corpus group.
-  ///
-  /// @return the current corpus group.
-  corpus_group_sptr&
-  get_corpus_group()
-  {return m_corpus_group;}
-
-  /// Setter of the corpus_group
-  ///
-  /// @param group the new corpus group.
-  void
-  set_corpus_group(const corpus_group_sptr& group)
-  {m_corpus_group = group;}
-
   /// Getter for the object that determines if a given declaration
   /// ought to be put in the set of exported decls of the current
   /// corpus.
@@ -789,34 +772,7 @@ public:
   /// @return the exported decls builder.
   corpus::exported_decls_builder*
   get_exported_decls_builder()
-  {return m_exported_decls_builder;}
-
-  /// Setter for the object that determines if a given declaration
-  /// ought to be put in the set of exported decls of the current
-  /// corpus.
-  ///
-  /// @param d the new exported decls builder.
-  ///
-  /// @return the exported decls builder.
-  void
-  set_exported_decls_builder(corpus::exported_decls_builder* d)
-  {m_exported_decls_builder = d;}
-
-  /// Getter of the vector of the suppression specifications
-  /// associated to the current read context.
-  ///
-  /// @return the vector of suppression specifications.
-  suppr::suppressions_type&
-  get_suppressions()
-  {return m_supprs;}
-
-  /// Getter of the vector of the suppression specifications
-  /// associated to the current read context.
-  ///
-  /// @return the vector of suppression specifications.
-  const suppr::suppressions_type&
-  get_suppressions() const
-  {return const_cast<read_context*>(this)->get_suppressions();}
+  {return corpus()->get_exported_decls_builder().get();}
 
   /// Test if there are suppression specifications (associated to the
   /// current corpus) that match a given SONAME or file name.
@@ -836,8 +792,8 @@ public:
     using suppr::file_suppression_sptr;
     using suppr::is_file_suppression;
 
-    for (suppressions_type::const_iterator s = get_suppressions().begin();
-	 s != get_suppressions().end();
+    for (suppressions_type::const_iterator s = suppressions().begin();
+	 s != suppressions().end();
 	 ++s)
       if (file_suppression_sptr suppr = is_file_suppression(*s))
 	if (suppr::suppression_matches_soname_or_filename(soname, filename,
@@ -847,41 +803,6 @@ public:
     return false;
   }
 
-  /// Add a given function to the set of exported functions of the
-  /// current corpus, if the function satisfies the different
-  /// constraints requirements.
-  ///
-  /// @param fn the function to consider.
-  void
-  maybe_add_fn_to_exported_decls(function_decl* fn)
-  {
-    if (fn)
-      if (corpus::exported_decls_builder* b = get_exported_decls_builder())
-	b->maybe_add_fn_to_exported_fns(fn);
-  }
-
-  /// Add a given variable to the set of exported functions of the
-  /// current corpus, if the function satisfies the different
-  /// constraints requirements.
-  ///
-  /// @param var the variable to consider.
-  void
-  maybe_add_var_to_exported_decls(var_decl* var)
-  {
-    if (var && var->get_scope())
-      if (corpus::exported_decls_builder* b = get_exported_decls_builder())
-	b->maybe_add_var_to_exported_vars(var);
-  }
-
-  /// Add a given variable to the set of exported functions of the
-  /// current corpus, if the function satisfies the different
-  /// constraints requirements.
-  ///
-  /// @param var the variable to consider.
-  void
-  maybe_add_var_to_exported_decls(const var_decl_sptr &var)
-  {return maybe_add_var_to_exported_decls(var.get());}
-
   /// Clear all the data that must absolutely be cleared at the end of
   /// the parsing of a translation unit.
   void
@@ -923,8 +844,8 @@ public:
   void
   maybe_check_abixml_canonical_type_stability(type_base_sptr& t)
   {
-    if (!m_env->self_comparison_debug_is_on()
-	|| m_env->get_type_id_canonical_type_map().empty())
+    if (!get_environment()->self_comparison_debug_is_on()
+	|| get_environment()->get_type_id_canonical_type_map().empty())
       return ;
 
     if (class_decl_sptr c = is_class_type(t))
@@ -936,15 +857,15 @@ public:
     // Let's get the type-id of this type as recorded in the
     // originating abixml file.
     string type_id =
-      m_env->get_type_id_from_pointer(reinterpret_cast<uintptr_t>(t.get()));
+      get_environment()->get_type_id_from_pointer(reinterpret_cast<uintptr_t>(t.get()));
 
     if (!type_id.empty())
       {
 	// Now let's get the canonical type that initially led to the
 	// serialization of a type with this type-id, when the abixml
 	// was being serialized.
-	auto j = m_env->get_type_id_canonical_type_map().find(type_id);
-	if (j == m_env->get_type_id_canonical_type_map().end())
+	auto j = get_environment()->get_type_id_canonical_type_map().find(type_id);
+	if (j == get_environment()->get_type_id_canonical_type_map().end())
 	  {
 	    if (t->get_naked_canonical_type())
 	      std::cerr << "error: no type with type-id: '"
@@ -1088,7 +1009,7 @@ public:
   bool
   suppression_can_match(const suppr::suppression_base& s) const
   {
-    corpus_sptr corp = get_corpus();
+    corpus_sptr corp = corpus();
 
     if (!s.priv_->matches_soname(corp->get_soname()))
       if (s.has_soname_related_property())
@@ -1129,88 +1050,6 @@ public:
     return suppr::suppression_matches_function_name(s, fn_name);
   }
 
-  /// Test whether if a given function suppression matches a function
-  /// designated by a regular expression that describes its linkage
-  /// name (symbol name).
-  ///
-  /// @param s the suppression specification to evaluate to see if it
-  /// matches a given function linkage name
-  ///
-  /// @param fn_linkage_name the linkage name of the function of interest.
-  ///
-  /// @return true iff the suppression specification @p s matches the
-  /// function whose linkage name is @p fn_linkage_name.
-  bool
-  suppression_matches_function_sym_name(const suppr::function_suppression_sptr& s,
-					const string& fn_linkage_name) const
-  {
-    if (!s)
-      return false;
-    return suppression_matches_function_sym_name(*s, fn_linkage_name);
-  }
-
-  /// Test whether if a given function suppression matches a function
-  /// designated by a regular expression that describes its linkage
-  /// name (symbol name).
-  ///
-  /// @param s the suppression specification to evaluate to see if it
-  /// matches a given function linkage name
-  ///
-  /// @param fn_linkage_name the linkage name of the function of interest.
-  ///
-  /// @return true iff the suppression specification @p s matches the
-  /// function whose linkage name is @p fn_linkage_name.
-  bool
-  suppression_matches_function_sym_name(const suppr::function_suppression& s,
-					const string& fn_linkage_name) const
-  {
-    if (!s.get_drops_artifact_from_ir()
-	|| !suppression_can_match(s))
-      return false;
-
-    return suppr::suppression_matches_function_sym_name(s, fn_linkage_name);
-  }
-
-  /// Test whether if a given variable suppression specification
-  /// matches a variable denoted by its name.
-  ///
-  /// @param s the variable suppression specification to consider.
-  ///
-  /// @param var_name the name of the variable to consider.
-  ///
-  /// @return true iff the suppression specification @p s matches the
-  /// variable whose name is @p var_name.
-  bool
-  suppression_matches_variable_name(const suppr::variable_suppression& s,
-				    const string& var_name) const
-  {
-    if (!s.get_drops_artifact_from_ir()
-	|| !suppression_can_match(s))
-      return false;
-
-    return suppr::suppression_matches_variable_name(s, var_name);
-  }
-
-  /// Test whether if a given variable suppression specification
-  /// matches a variable denoted by its linkage name.
-  ///
-  /// @param s the variable suppression specification to consider.
-  ///
-  /// @param var_linkage_name the linkage name of the variable to consider.
-  ///
-  /// @return true iff variable suppression specification @p s matches
-  /// the variable denoted by linkage name @p var_linkage_name.
-  bool
-  suppression_matches_variable_sym_name(const suppr::variable_suppression& s,
-					const string& var_linkage_name) const
-  {
-    if (!s.get_drops_artifact_from_ir()
-	|| !suppression_can_match(s))
-      return false;
-
-    return suppr::suppression_matches_variable_sym_name(s, var_linkage_name);
-  }
-
   /// Test if a given type suppression specification matches a type
   /// designated by its name and location.
   ///
@@ -1233,19 +1072,212 @@ public:
     return suppr::suppression_matches_type_name_or_location(s, type_name,
 							    type_location);
   }
-};// end class read_context
 
-static int	advance_cursor(read_context&);
-static bool read_translation_unit(read_context&, translation_unit&, xmlNodePtr);
-static translation_unit_sptr get_or_read_and_add_translation_unit(read_context&, xmlNodePtr);
-static translation_unit_sptr read_translation_unit_from_input(read_context&);
-static bool	read_symbol_db_from_input(read_context&,
+  virtual ir::corpus_sptr
+  read_corpus(fe_iface::status& status)
+  {
+    corpus_sptr nil;
+
+    xml::reader_sptr xml_reader = get_libxml_reader();
+    if (!xml_reader)
+      return nil;
+
+    // This is to remember to call xmlTextReaderNext if we ever call
+    // xmlTextReaderExpand.
+    bool call_reader_next = false;
+
+    xmlNodePtr node = get_corpus_node();
+    if (!node)
+      {
+	// The document must start with the abi-corpus node.
+	int status = 1;
+	while (status == 1
+	       && XML_READER_GET_NODE_TYPE(xml_reader) != XML_READER_TYPE_ELEMENT)
+	  status = advance_cursor (*this);
+
+	if (status != 1 || !xmlStrEqual (XML_READER_GET_NODE_NAME(xml_reader).get(),
+					 BAD_CAST("abi-corpus")))
+	  return nil;
+
+#ifdef WITH_DEBUG_SELF_COMPARISON
+	if (get_environment()->self_comparison_debug_is_on())
+	  get_environment()->
+	    set_self_comparison_debug_input(corpus());
+#endif
+
+	if (!corpus_group())
+	  clear_per_corpus_data();
+
+	ir::corpus& corp = *corpus();
+
+	corp.set_origin(corpus::NATIVE_XML_ORIGIN);
+
+	handle_version_attribute(xml_reader, corp);
+
+	xml::xml_char_sptr path_str = XML_READER_GET_ATTRIBUTE(xml_reader, "path");
+	string path;
+
+	if (path_str)
+	  {
+	    path = reinterpret_cast<char*>(path_str.get());
+	    corpus_path(path);
+	    corp.set_path(path);
+	  }
+
+	xml::xml_char_sptr architecture_str =
+	  XML_READER_GET_ATTRIBUTE(xml_reader, "architecture");
+	if (architecture_str)
+	  corp.set_architecture_name
+	    (reinterpret_cast<char*>(architecture_str.get()));
+
+	xml::xml_char_sptr soname_str =
+	  XML_READER_GET_ATTRIBUTE(xml_reader, "soname");
+	string soname;
+
+	if (soname_str)
+	  {
+	    soname = reinterpret_cast<char*>(soname_str.get());
+	    dt_soname(soname);
+	    corp.set_soname(soname);
+	  }
+
+	// Apply suppression specifications here to honour:
+	//
+	//   [suppress_file]
+	//     (soname_regexp
+	//      |soname_not_regexp
+	//      |file_name_regexp
+	//      |file_name_not_regexp) = <soname-or-file-name>
+	if ((!soname.empty() || !path.empty())
+	    && corpus_is_suppressed_by_soname_or_filename(soname, path))
+	  return nil;
+
+	node = xmlTextReaderExpand(xml_reader.get());
+	if (!node)
+	  return nil;
+
+	call_reader_next = true;
+      }
+    else
+      {
+#ifdef WITH_DEBUG_SELF_COMPARISON
+	if (get_environment()->self_comparison_debug_is_on())
+	  get_environment()->
+	    set_self_comparison_debug_input(corpus());
+#endif
+
+	if (!corpus_group())
+	  clear_per_corpus_data();
+
+	ir::corpus& corp = *corpus();
+	corp.set_origin(corpus::NATIVE_XML_ORIGIN);
+
+	xml::xml_char_sptr path_str = XML_NODE_GET_ATTRIBUTE(node, "path");
+	if (path_str)
+	  corp.set_path(reinterpret_cast<char*>(path_str.get()));
+
+	xml::xml_char_sptr architecture_str =
+	  XML_NODE_GET_ATTRIBUTE(node, "architecture");
+	if (architecture_str)
+	  corp.set_architecture_name
+	    (reinterpret_cast<char*>(architecture_str.get()));
+
+	xml::xml_char_sptr soname_str =
+	  XML_NODE_GET_ATTRIBUTE(node, "soname");
+	if (soname_str)
+	  corp.set_soname(reinterpret_cast<char*>(soname_str.get()));
+      }
+
+    // If the corpus element node has children nodes, make
+    // get_corpus_node() returns the first child element node of
+    // the corpus element that *needs* to be processed.
+    if (node->children)
+      {
+	xmlNodePtr n = xmlFirstElementChild(node);
+	set_corpus_node(n);
+      }
+
+    ir::corpus& corp = *corpus();
+
+    walk_xml_node_to_map_type_ids(*this, node);
+
+    // Read the needed element
+    vector<string> needed;
+    read_elf_needed_from_input(*this, needed);
+    if (!needed.empty())
+      corp.set_needed(needed);
+
+    string_elf_symbols_map_sptr fn_sym_db, var_sym_db;
+
+    // Read the symbol databases.
+    read_symbol_db_from_input(*this, fn_sym_db, var_sym_db);
+
+    // Note that it's possible that both fn_sym_db and var_sym_db are nil,
+    // due to potential suppression specifications.  That's fine.
+    corp.set_symtab(symtab_reader::symtab::load(fn_sym_db, var_sym_db));
+
+    get_environment().canonicalization_is_done(false);
+
+    // Read the translation units.
+    while (read_translation_unit_from_input(*this))
+      ;
+
+    if (tracking_non_reachable_types())
+      {
+	bool is_tracking_non_reachable_types = false;
+	read_tracking_non_reachable_types(node, is_tracking_non_reachable_types);
+
+	ABG_ASSERT
+	  (corp.recording_types_reachable_from_public_interface_supported()
+	   == is_tracking_non_reachable_types);
+      }
+
+
+    perform_late_type_canonicalizing();
+
+    get_environment().canonicalization_is_done(true);
+
+    if (call_reader_next)
+      {
+	// This is the necessary counter-part of the xmlTextReaderExpand()
+	// call at the beginning of the function.
+	xmlTextReaderNext(xml_reader.get());
+	// The call above invalidates the xml node returned by
+	// xmlTextReaderExpand, which is can still be accessed via
+	// set_corpus_node.
+	set_corpus_node(0);
+      }
+    else
+      {
+	node = get_corpus_node();
+	node = xmlNextElementSibling(node);
+	if (!node)
+	  {
+	    node = get_corpus_node();
+	    if (node)
+	      node = xmlNextElementSibling(node->parent);
+	  }
+	set_corpus_node(node);
+      }
+
+    status = STATUS_OK;
+    return corpus();
+  }
+};// end class reader
+
+typedef shared_ptr<reader> reader_sptr;
+
+static int	advance_cursor(reader&);
+static bool read_translation_unit(fe_iface&, translation_unit&, xmlNodePtr);
+static translation_unit_sptr get_or_read_and_add_translation_unit(reader&, xmlNodePtr);
+static translation_unit_sptr read_translation_unit_from_input(fe_iface&);
+static bool	read_symbol_db_from_input(reader&,
 					  string_elf_symbols_map_sptr&,
 					  string_elf_symbols_map_sptr&);
-static bool	read_location(const read_context&, xmlNodePtr, location&);
-static bool	read_artificial_location(const read_context&,
+static bool	read_location(const reader&, xmlNodePtr, location&);
+static bool	read_artificial_location(const reader&,
 					 xmlNodePtr, location&);
-static bool     maybe_set_artificial_location(const read_context&,
+static bool     maybe_set_artificial_location(const reader&,
 					      xmlNodePtr,
 					      type_or_decl_base_sptr);
 static bool	read_visibility(xmlNodePtr, decl_base::visibility&);
@@ -1264,7 +1296,7 @@ static bool	read_elf_symbol_visibility(xmlNodePtr,
 					   elf_symbol::visibility&);
 
 static namespace_decl_sptr
-build_namespace_decl(read_context&, const xmlNodePtr, bool);
+build_namespace_decl(reader&, const xmlNodePtr, bool);
 
 // <build a c++ class from an instance of xmlNodePtr>
 //
@@ -1274,96 +1306,96 @@ build_namespace_decl(read_context&, const xmlNodePtr, bool);
 // below.
 
 static elf_symbol_sptr
-build_elf_symbol(read_context&, const xmlNodePtr, bool);
+build_elf_symbol(reader&, const xmlNodePtr, bool);
 
 static elf_symbol_sptr
-build_elf_symbol_from_reference(read_context&, const xmlNodePtr);
+build_elf_symbol_from_reference(reader&, const xmlNodePtr);
 
 static string_elf_symbols_map_sptr
-build_elf_symbol_db(read_context&, const xmlNodePtr, bool);
+build_elf_symbol_db(reader&, const xmlNodePtr, bool);
 
 static function_decl::parameter_sptr
-build_function_parameter (read_context&, const xmlNodePtr);
+build_function_parameter (reader&, const xmlNodePtr);
 
 static function_decl_sptr
-build_function_decl(read_context&, const xmlNodePtr,
+build_function_decl(reader&, const xmlNodePtr,
 		    class_or_union_sptr, bool);
 
 static function_decl_sptr
-build_function_decl_if_not_suppressed(read_context&, const xmlNodePtr,
+build_function_decl_if_not_suppressed(reader&, const xmlNodePtr,
 				      class_or_union_sptr, bool);
 
 static bool
-function_is_suppressed(const read_context& ctxt,
+function_is_suppressed(const reader& rdr,
 		       xmlNodePtr node);
 
 static var_decl_sptr
-build_var_decl_if_not_suppressed(read_context&, const xmlNodePtr, bool);
+build_var_decl_if_not_suppressed(reader&, const xmlNodePtr, bool);
 
 static var_decl_sptr
-build_var_decl(read_context&, const xmlNodePtr, bool);
+build_var_decl(reader&, const xmlNodePtr, bool);
 
 static bool
-variable_is_suppressed(const read_context& ctxt,
+variable_is_suppressed(const reader& rdr,
 		       xmlNodePtr node);
 
 static shared_ptr<type_decl>
-build_type_decl(read_context&, const xmlNodePtr, bool);
+build_type_decl(reader&, const xmlNodePtr, bool);
 
 static qualified_type_def_sptr
-build_qualified_type_decl(read_context&, const xmlNodePtr, bool);
+build_qualified_type_decl(reader&, const xmlNodePtr, bool);
 
 static shared_ptr<pointer_type_def>
-build_pointer_type_def(read_context&, const xmlNodePtr, bool);
+build_pointer_type_def(reader&, const xmlNodePtr, bool);
 
 static shared_ptr<reference_type_def>
-build_reference_type_def(read_context&, const xmlNodePtr, bool);
+build_reference_type_def(reader&, const xmlNodePtr, bool);
 
 static shared_ptr<function_type>
-build_function_type(read_context&, const xmlNodePtr, bool);
+build_function_type(reader&, const xmlNodePtr, bool);
 
 static array_type_def::subrange_sptr
-build_subrange_type(read_context&, const xmlNodePtr);
+build_subrange_type(reader&, const xmlNodePtr);
 
 static array_type_def_sptr
-build_array_type_def(read_context&, const xmlNodePtr, bool);
+build_array_type_def(reader&, const xmlNodePtr, bool);
 
 static enum_type_decl_sptr
-build_enum_type_decl(read_context&, const xmlNodePtr, bool);
+build_enum_type_decl(reader&, const xmlNodePtr, bool);
 
 static shared_ptr<typedef_decl>
-build_typedef_decl(read_context&, const xmlNodePtr, bool);
+build_typedef_decl(reader&, const xmlNodePtr, bool);
 
 static class_decl_sptr
-build_class_decl(read_context&, const xmlNodePtr, bool);
+build_class_decl(reader&, const xmlNodePtr, bool);
 
 static union_decl_sptr
-build_union_decl(read_context&, const xmlNodePtr, bool);
+build_union_decl(reader&, const xmlNodePtr, bool);
 
 static shared_ptr<function_tdecl>
-build_function_tdecl(read_context&, const xmlNodePtr, bool);
+build_function_tdecl(reader&, const xmlNodePtr, bool);
 
 static shared_ptr<class_tdecl>
-build_class_tdecl(read_context&, const xmlNodePtr, bool);
+build_class_tdecl(reader&, const xmlNodePtr, bool);
 
 static type_tparameter_sptr
-build_type_tparameter(read_context&, const xmlNodePtr,
+build_type_tparameter(reader&, const xmlNodePtr,
 		      unsigned, template_decl_sptr);
 
 static type_composition_sptr
-build_type_composition(read_context&, const xmlNodePtr,
+build_type_composition(reader&, const xmlNodePtr,
 		       unsigned, template_decl_sptr);
 
 static non_type_tparameter_sptr
-build_non_type_tparameter(read_context&, const xmlNodePtr,
+build_non_type_tparameter(reader&, const xmlNodePtr,
 			  unsigned, template_decl_sptr);
 
 static template_tparameter_sptr
-build_template_tparameter(read_context&, const xmlNodePtr,
+build_template_tparameter(reader&, const xmlNodePtr,
 			  unsigned, template_decl_sptr);
 
 static template_parameter_sptr
-build_template_parameter(read_context&, const xmlNodePtr,
+build_template_parameter(reader&, const xmlNodePtr,
 			 unsigned, template_decl_sptr);
 
 // Please make this build_type function be the last one of the list.
@@ -1371,42 +1403,42 @@ build_template_parameter(read_context&, const xmlNodePtr,
 // please make sure to update it accordingly, whenever a new
 // type-building function is added here.
 static shared_ptr<type_base>
-build_type(read_context&, const xmlNodePtr, bool);
+build_type(reader&, const xmlNodePtr, bool);
 // </build a c++ class  from an instance of xmlNodePtr>
 
-static type_or_decl_base_sptr	handle_element_node(read_context&, xmlNodePtr, bool);
-static decl_base_sptr	handle_type_decl(read_context&, xmlNodePtr, bool);
-static decl_base_sptr	handle_namespace_decl(read_context&, xmlNodePtr, bool);
-static decl_base_sptr	handle_qualified_type_decl(read_context&,
+static type_or_decl_base_sptr	handle_element_node(reader&, xmlNodePtr, bool);
+static decl_base_sptr	handle_type_decl(reader&, xmlNodePtr, bool);
+static decl_base_sptr	handle_namespace_decl(reader&, xmlNodePtr, bool);
+static decl_base_sptr	handle_qualified_type_decl(reader&,
 						   xmlNodePtr, bool);
-static decl_base_sptr	handle_pointer_type_def(read_context&,
+static decl_base_sptr	handle_pointer_type_def(reader&,
 						xmlNodePtr, bool);
-static decl_base_sptr	handle_reference_type_def(read_context&,
+static decl_base_sptr	handle_reference_type_def(reader&,
 						  xmlNodePtr, bool);
-static type_base_sptr	handle_function_type(read_context&,
+static type_base_sptr	handle_function_type(reader&,
 					     xmlNodePtr, bool);
-static decl_base_sptr	handle_array_type_def(read_context&,
+static decl_base_sptr	handle_array_type_def(reader&,
 					      xmlNodePtr, bool);
-static decl_base_sptr	handle_enum_type_decl(read_context&, xmlNodePtr, bool);
-static decl_base_sptr	handle_typedef_decl(read_context&, xmlNodePtr, bool);
-static decl_base_sptr	handle_var_decl(read_context&, xmlNodePtr, bool);
-static decl_base_sptr	handle_function_decl(read_context&, xmlNodePtr, bool);
-static decl_base_sptr	handle_class_decl(read_context&, xmlNodePtr, bool);
-static decl_base_sptr	handle_union_decl(read_context&, xmlNodePtr, bool);
-static decl_base_sptr	handle_function_tdecl(read_context&, xmlNodePtr, bool);
-static decl_base_sptr	handle_class_tdecl(read_context&, xmlNodePtr, bool);
+static decl_base_sptr	handle_enum_type_decl(reader&, xmlNodePtr, bool);
+static decl_base_sptr	handle_typedef_decl(reader&, xmlNodePtr, bool);
+static decl_base_sptr	handle_var_decl(reader&, xmlNodePtr, bool);
+static decl_base_sptr	handle_function_decl(reader&, xmlNodePtr, bool);
+static decl_base_sptr	handle_class_decl(reader&, xmlNodePtr, bool);
+static decl_base_sptr	handle_union_decl(reader&, xmlNodePtr, bool);
+static decl_base_sptr	handle_function_tdecl(reader&, xmlNodePtr, bool);
+static decl_base_sptr	handle_class_tdecl(reader&, xmlNodePtr, bool);
 
 #ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
-#define RECORD_ARTIFACT_AS_USED_BY(ctxt, used, user) \
-  ctxt.record_artifact_as_used_by(used,user)
-#define RECORD_ARTIFACTS_AS_USED_IN_FN_DECL(ctxt, fn) \
-  ctxt.record_artifacts_as_used_in_fn_decl(fn)
-#define RECORD_ARTIFACTS_AS_USED_IN_FN_TYPE(ctxt, fn_type)\
-  ctxt.record_artifacts_as_used_in_fn_type(fn_type)
+#define RECORD_ARTIFACT_AS_USED_BY(rdr, used, user) \
+  rdr.record_artifact_as_used_by(used,user)
+#define RECORD_ARTIFACTS_AS_USED_IN_FN_DECL(rdr, fn) \
+  rdr.record_artifacts_as_used_in_fn_decl(fn)
+#define RECORD_ARTIFACTS_AS_USED_IN_FN_TYPE(rdr, fn_type)\
+  rdr.record_artifacts_as_used_in_fn_type(fn_type)
 #else
-#define RECORD_ARTIFACT_AS_USED_BY(ctxt, used, user)
-#define RECORD_ARTIFACTS_AS_USED_IN_FN_DECL(ctxt, fn)
-#define RECORD_ARTIFACTS_AS_USED_IN_FN_TYPE(ctxt, fn_type)
+#define RECORD_ARTIFACT_AS_USED_BY(rdr, used, user)
+#define RECORD_ARTIFACTS_AS_USED_IN_FN_DECL(rdr, fn)
+#define RECORD_ARTIFACTS_AS_USED_IN_FN_TYPE(rdr, fn_type)
 #endif
 
 /// Get the IR node representing the scope for a given XML node.
@@ -1423,7 +1455,7 @@ static decl_base_sptr	handle_class_tdecl(read_context&, xmlNodePtr, bool);
 /// @return the IR node representing the scope of the IR node for the
 /// XML node given in argument.
 scope_decl_sptr
-read_context::get_scope_for_node(xmlNodePtr node,
+reader::get_scope_for_node(xmlNodePtr node,
 				 access_specifier& access)
 {
   scope_decl_sptr nil, scope;
@@ -1477,7 +1509,7 @@ read_context::get_scope_for_node(xmlNodePtr node,
 ///
 /// @return the type declaration for the ID given in parameter.
 type_base_sptr
-read_context::build_or_get_type_decl(const string& id,
+reader::build_or_get_type_decl(const string& id,
 				     bool add_decl_to_scope)
 {
   type_base_sptr t = get_type_decl(id);
@@ -1528,12 +1560,12 @@ read_context::build_or_get_type_decl(const string& id,
 /// document.  Return 1 of the parsing was successful, 0 if no input
 /// xml token is left, or -1 in case of error.
 ///
-/// @param ctxt the read context
+/// @param rdr the ABIXML reader
 ///
 static int
-advance_cursor(read_context& ctxt)
+advance_cursor(reader& rdr)
 {
-  xml::reader_sptr reader = ctxt.get_reader();
+  xml::reader_sptr reader = rdr.get_libxml_reader();
   return xmlTextReaderRead(reader.get());
 }
 
@@ -1541,12 +1573,12 @@ advance_cursor(read_context& ctxt)
 /// the value of the 'id' attribute (for type definitions) and the value
 /// is the xml node containing the 'id' attribute.
 ///
-/// @param ctxt the context of the reader.
+/// @param rdr the context of the reader.
 ///
 /// @param node the XML sub-tree node to walk.  It must be an element
 /// node.
 static void
-walk_xml_node_to_map_type_ids(read_context& ctxt,
+walk_xml_node_to_map_type_ids(reader& rdr,
 			      xmlNodePtr node)
 {
   xmlNodePtr n = node;
@@ -1557,17 +1589,20 @@ walk_xml_node_to_map_type_ids(read_context& ctxt,
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(n, "id"))
     {
       string id = CHAR_STR(s);
-      ctxt.map_id_and_node(id, n);
+      rdr.map_id_and_node(id, n);
     }
 
   for (n = xmlFirstElementChild(n); n; n = xmlNextElementSibling(n))
-    walk_xml_node_to_map_type_ids(ctxt, n);
+    walk_xml_node_to_map_type_ids(rdr, n);
 }
 
 static bool
-read_translation_unit(read_context& ctxt, translation_unit& tu, xmlNodePtr node)
+read_translation_unit(fe_iface& iface, translation_unit& tu, xmlNodePtr node)
 {
-  tu.set_corpus(ctxt.get_corpus().get());
+  abixml_reader::reader& rdr = dynamic_cast<abixml_reader::reader&>(iface);
+
+  if (!rdr.corpus()->is_empty())
+    tu.set_corpus(rdr.corpus().get());
 
   xml::xml_char_sptr addrsize_str =
     XML_NODE_GET_ATTRIBUTE(node, "address-size");
@@ -1595,25 +1630,25 @@ read_translation_unit(read_context& ctxt, translation_unit& tu, xmlNodePtr node)
 
   // We are at global scope, as we've just seen the top-most
   // "abi-instr" element.
-  ctxt.push_decl(tu.get_global_scope());
-  ctxt.map_xml_node_to_decl(node, tu.get_global_scope());
+  rdr.push_decl(tu.get_global_scope());
+  rdr.map_xml_node_to_decl(node, tu.get_global_scope());
 
-  if (ctxt.get_id_xml_node_map().empty()
-      || !ctxt.get_corpus())
-    walk_xml_node_to_map_type_ids(ctxt, node);
+  if (rdr.get_id_xml_node_map().empty()
+      || !rdr.corpus())
+    walk_xml_node_to_map_type_ids(rdr, node);
 
   for (xmlNodePtr n = xmlFirstElementChild(node);
        n;
        n = xmlNextElementSibling(n))
-    handle_element_node(ctxt, n, /*add_decl_to_scope=*/true);
+    handle_element_node(rdr, n, /*add_decl_to_scope=*/true);
 
-  ctxt.pop_scope_or_abort(tu.get_global_scope());
+  rdr.pop_scope_or_abort(tu.get_global_scope());
 
-  xml::reader_sptr reader = ctxt.get_reader();
+  xml::reader_sptr reader = rdr.get_libxml_reader();
   if (!reader)
     return false;
 
-  ctxt.clear_per_translation_unit_data();
+  rdr.clear_per_translation_unit_data();
 
   return true;
 }
@@ -1626,15 +1661,15 @@ read_translation_unit(read_context& ctxt, translation_unit& tu, xmlNodePtr node)
 /// @ref translation_unit out of it, add it to the current corpus and
 /// return it.
 ///
-/// @param ctxt the read context.
+/// @param rdr the ABIXML reader.
 ///
 /// @param node the XML node to consider.
 ///
 /// @return the resulting translation unit.
 static translation_unit_sptr
-get_or_read_and_add_translation_unit(read_context& ctxt, xmlNodePtr node)
+get_or_read_and_add_translation_unit(reader& rdr, xmlNodePtr node)
 {
-  corpus_sptr corp = ctxt.get_corpus();
+  corpus_sptr corp = rdr.corpus();
 
   translation_unit_sptr tu;
   string tu_path;
@@ -1645,18 +1680,18 @@ get_or_read_and_add_translation_unit(read_context& ctxt, xmlNodePtr node)
       tu_path = reinterpret_cast<char*>(path_str.get());
       ABG_ASSERT(!tu_path.empty());
 
-      if (corp)
+      if (corp && !corp->is_empty())
 	tu = corp->find_translation_unit(tu_path);
 
       if (tu)
 	return tu;
     }
 
-  tu.reset(new translation_unit(ctxt.get_environment(), tu_path));
-  if (corp)
+  tu.reset(new translation_unit(rdr.get_environment(), tu_path));
+  if (corp && !corp->is_empty())
     corp->add(tu);
 
-  if (read_translation_unit(ctxt, *tu, node))
+  if (read_translation_unit(rdr, *tu, node))
     return tu;
 
   return translation_unit_sptr();
@@ -1666,19 +1701,21 @@ get_or_read_and_add_translation_unit(read_context& ctxt, xmlNodePtr node)
 /// represented by an 'abi-instr' element node, associated to the current
 /// context.
 ///
-/// @param ctxt the current input context
+/// @param rdr the current input context
 ///
 /// @return the translation unit resulting from the parsing upon
 /// successful completion, or nil.
 static translation_unit_sptr
-read_translation_unit_from_input(read_context&	ctxt)
+read_translation_unit_from_input(fe_iface& iface)
 {
   translation_unit_sptr tu, nil;
 
-  xmlNodePtr node = ctxt.get_corpus_node();
+  abixml_reader::reader& rdr = dynamic_cast<abixml_reader::reader&>(iface);
+
+  xmlNodePtr node = rdr.get_corpus_node();
   if (!node)
     {
-      xml::reader_sptr reader = ctxt.get_reader();
+      xml::reader_sptr reader = rdr.get_libxml_reader();
       if (!reader)
 	return nil;
 
@@ -1686,7 +1723,7 @@ read_translation_unit_from_input(read_context&	ctxt)
       int status = 1;
       while (status == 1
 	     && XML_READER_GET_NODE_TYPE(reader) != XML_READER_TYPE_ELEMENT)
-	status = advance_cursor (ctxt);
+	status = advance_cursor (rdr);
 
       if (status != 1 || !xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(),
 				       BAD_CAST("abi-instr")))
@@ -1699,7 +1736,7 @@ read_translation_unit_from_input(read_context&	ctxt)
   else
     {
       node = 0;
-      for (xmlNodePtr n = ctxt.get_corpus_node();
+      for (xmlNodePtr n = rdr.get_corpus_node();
 	   n;
 	   n = xmlNextElementSibling(n))
 	{
@@ -1713,16 +1750,16 @@ read_translation_unit_from_input(read_context&	ctxt)
   if (node == 0)
     return nil;
 
-  tu = get_or_read_and_add_translation_unit(ctxt, node);
+  tu = get_or_read_and_add_translation_unit(rdr, node);
 
-  if (ctxt.get_corpus_node())
+  if (rdr.get_corpus_node())
     {
       // We are not in the mode where the current corpus node came
       // from a local invocation of xmlTextReaderExpand.  So let's set
-      // ctxt.get_corpus_node to the next child element node of the
+      // rdr.get_corpus_node to the next child element node of the
       // corpus that needs to be processed.
       node = xmlNextElementSibling(node);
-      ctxt.set_corpus_node(node);
+      rdr.set_corpus_node(node);
     }
 
   return tu;
@@ -1736,7 +1773,7 @@ read_translation_unit_from_input(read_context&	ctxt)
 /// element named "elf-variable-symbols."  They contains "elf-symbol"
 /// XML elements.
 ///
-/// @param ctxt the read_context to use for the parsing.
+/// @param rdr the reader to use for the parsing.
 ///
 /// @param fn_symdb any resulting function symbol database object, if
 /// elf-function-symbols was present.
@@ -1746,21 +1783,21 @@ read_translation_unit_from_input(read_context&	ctxt)
 ///
 /// @return true upon successful parsing, false otherwise.
 static bool
-read_symbol_db_from_input(read_context&		 ctxt,
+read_symbol_db_from_input(reader&		 rdr,
 			  string_elf_symbols_map_sptr& fn_symdb,
 			  string_elf_symbols_map_sptr& var_symdb)
 {
-  xml::reader_sptr reader = ctxt.get_reader();
+  xml::reader_sptr reader = rdr.get_libxml_reader();
   if (!reader)
     return false;
 
-  if (!ctxt.get_corpus_node())
+  if (!rdr.get_corpus_node())
     for (;;)
       {
 	int status = 1;
 	while (status == 1
 	       && XML_READER_GET_NODE_TYPE(reader) != XML_READER_TYPE_ELEMENT)
-	  status = advance_cursor (ctxt);
+	  status = advance_cursor (rdr);
 
 	if (status != 1)
 	  return false;
@@ -1780,14 +1817,14 @@ read_symbol_db_from_input(read_context&		 ctxt,
 	  return false;
 
 	if (has_fn_syms)
-	  fn_symdb = build_elf_symbol_db(ctxt, node, true);
+	  fn_symdb = build_elf_symbol_db(rdr, node, true);
 	else if (has_var_syms)
-	  var_symdb = build_elf_symbol_db(ctxt, node, false);
+	  var_symdb = build_elf_symbol_db(rdr, node, false);
 
 	xmlTextReaderNext(reader.get());
       }
   else
-    for (xmlNodePtr n = ctxt.get_corpus_node(); n; n = xmlNextElementSibling(n))
+    for (xmlNodePtr n = rdr.get_corpus_node(); n; n = xmlNextElementSibling(n))
       {
 	bool has_fn_syms = false, has_var_syms = false;
 	if (xmlStrEqual(n->name, BAD_CAST("elf-function-symbols")))
@@ -1796,14 +1833,14 @@ read_symbol_db_from_input(read_context&		 ctxt,
 	  has_var_syms = true;
 	else
 	  {
-	    ctxt.set_corpus_node(n);
+	    rdr.set_corpus_node(n);
 	    break;
 	  }
 
 	if (has_fn_syms)
-	  fn_symdb = build_elf_symbol_db(ctxt, n, true);
+	  fn_symdb = build_elf_symbol_db(rdr, n, true);
 	else if (has_var_syms)
-	  var_symdb = build_elf_symbol_db(ctxt, n, false);
+	  var_symdb = build_elf_symbol_db(rdr, n, false);
 	else
 	  break;
       }
@@ -1849,27 +1886,27 @@ build_needed(xmlNode* node, vector<string>& needed)
 /// "elf-needed".  Then read the sub-tree to made of that node and
 /// extracts a vector of needed dependencies name from it.
 ///
-/// @param ctxt the read context used to the xml reading.
+/// @param rdr the ABIXML reader used to the xml reading.
 ///
 /// @param needed the resulting vector of dependency names.
 ///
 /// @return true upon successful completion, false otherwise.
 static bool
-read_elf_needed_from_input(read_context&	ctxt,
+read_elf_needed_from_input(reader&	rdr,
 			   vector<string>&	needed)
 {
-  xml::reader_sptr reader = ctxt.get_reader();
+  xml::reader_sptr reader = rdr.get_libxml_reader();
   if (!reader)
     return false;
 
   xmlNodePtr node = 0;
 
-  if (ctxt.get_corpus_node() == 0)
+  if (rdr.get_corpus_node() == 0)
     {
       int status = 1;
       while (status == 1
 	     && XML_READER_GET_NODE_TYPE(reader) != XML_READER_TYPE_ELEMENT)
-	status = advance_cursor (ctxt);
+	status = advance_cursor (rdr);
 
       if (status != 1)
 	return false;
@@ -1884,7 +1921,7 @@ read_elf_needed_from_input(read_context&	ctxt,
     }
   else
     {
-      for (xmlNodePtr n = ctxt.get_corpus_node();
+      for (xmlNodePtr n = rdr.get_corpus_node();
 	   n;
 	   n = xmlNextElementSibling(n))
 	{
@@ -1900,7 +1937,7 @@ read_elf_needed_from_input(read_context&	ctxt,
     {
       result = build_needed(node, needed);
       node = xmlNextElementSibling(node);
-      ctxt.set_corpus_node(node);
+      rdr.set_corpus_node(node);
     }
 
   return result;
@@ -1925,35 +1962,38 @@ read_elf_needed_from_input(read_context&	ctxt,
 /// @ref diff_context type to learn how to set suppressions that are
 /// to be used in that context.
 ///
-/// @param ctxt the context that is going to be used by functions that
+/// @param rdr the context that is going to be used by functions that
 /// read types and declarations information to construct and ABI
 /// corpus.
 ///
 /// @param supprs the suppression specifications to be applied during
 /// the construction of the ABI corpus.
 void
-add_read_context_suppressions(read_context& ctxt,
-			      const suppr::suppressions_type& supprs)
+add_reader_suppressions(reader& rdr,
+			const suppr::suppressions_type& supprs)
 {
   for (suppr::suppressions_type::const_iterator i = supprs.begin();
        i != supprs.end();
        ++i)
     if ((*i)->get_drops_artifact_from_ir())
-      ctxt.get_suppressions().push_back(*i);
+      rdr.suppressions().push_back(*i);
 }
 
-/// Configure the @ref read_context so that types not reachable from
+/// Configure the @ref reader so that types not reachable from
 /// public interface are taken into account when the abixml file is
 /// read.
 ///
-/// @param ctxt the @read_context to consider.
+/// @param rdr the @reader to consider.
 ///
 /// @param flag if yes, then types not reachable from public interface
 /// are taken into account when the abixml file is read.
 void
-consider_types_not_reachable_from_public_interfaces(read_context& ctxt,
+consider_types_not_reachable_from_public_interfaces(fe_iface& iface,
 						    bool flag)
-{ctxt.tracking_non_reachable_types(flag);}
+{
+  abixml_reader::reader& rdr = dynamic_cast<abixml_reader::reader&>(iface);
+  rdr.tracking_non_reachable_types(flag);
+}
 
 #ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
 /// Get the vector of types that have a given type-id.
@@ -1961,14 +2001,15 @@ consider_types_not_reachable_from_public_interfaces(read_context& ctxt,
 /// This function is available only if the project has been configured
 /// with --enable-show-type-use-in-abilint.
 ///
-/// @param ctxt the abixml text reader context to use.
+/// @param rdr the abixml text reader context to use.
 ///
 /// @param type_id the type-id to consider.
 vector<type_base_sptr>*
-get_types_from_type_id(read_context& ctxt, const string& type_id)
+get_types_from_type_id(fe_iface& iface, const string& type_id)
 {
-  auto it = ctxt.m_types_map.find(type_id);
-  if (it == ctxt.m_types_map.end())
+  xml_reader::reader& rdr = dynamic_cast<xml_reader::reader&>(iface);
+  auto it = rdr.m_types_map.find(type_id);
+  if (it == rdr.m_types_map.end())
     return nullptr;
   return &it->second;
 }
@@ -1978,10 +2019,13 @@ get_types_from_type_id(read_context& ctxt, const string& type_id)
 /// This function is available only if the project has been configured
 /// with --enable-show-type-use-in-abilint.
 ///
-/// @param ctxt the abixml text reader context to use.
+/// @param rdr the abixml text reader context to use.
 unordered_map<type_or_decl_base*, vector<type_or_decl_base*>>*
-get_artifact_used_by_relation_map(read_context& ctxt)
-{return &ctxt.m_artifact_used_by_map;}
+get_artifact_used_by_relation_map(fe_iface& iface)
+{
+  xml_reader::reader& rdr = dynamic_cast<xml_reader::reader&>(iface);
+  return &rdr.m_artifact_used_by_map;
+}
 #endif
 
 /// Read the "version" attribute from the current XML element which is
@@ -2016,217 +2060,20 @@ handle_version_attribute(xml::reader_sptr& reader, corpus& corp)
   corp.set_format_minor_version_number(v[1]);
 }
 
-/// Parse the input XML document containing an ABI corpus, represented
-/// by an 'abi-corpus' element node, associated to the current
-/// context.
-///
-/// @param ctxt the current input context.
-///
-/// @return the corpus resulting from the parsing
-corpus_sptr
-read_corpus_from_input(read_context& ctxt)
-{
-  corpus_sptr nil;
-
-  xml::reader_sptr reader = ctxt.get_reader();
-  if (!reader)
-    return nil;
-
-  // This is to remember to call xmlTextReaderNext if we ever call
-  // xmlTextReaderExpand.
-  bool call_reader_next = false;
-
-  xmlNodePtr node = ctxt.get_corpus_node();
-  if (!node)
-    {
-      // The document must start with the abi-corpus node.
-      int status = 1;
-      while (status == 1
-	     && XML_READER_GET_NODE_TYPE(reader) != XML_READER_TYPE_ELEMENT)
-	status = advance_cursor (ctxt);
-
-      if (status != 1 || !xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(),
-				       BAD_CAST("abi-corpus")))
-	return nil;
-
-      ctxt.set_corpus(std::make_shared<corpus>(ctxt.get_environment(), ""));
-#ifdef WITH_DEBUG_SELF_COMPARISON
-      if (ctxt.get_environment()->self_comparison_debug_is_on())
-	ctxt.get_environment()->
-	  set_self_comparison_debug_input(ctxt.get_corpus());
-#endif
-
-      if (!ctxt.get_corpus_group())
-	ctxt.clear_per_corpus_data();
-
-      corpus& corp = *ctxt.get_corpus();
-      corp.set_origin(corpus::NATIVE_XML_ORIGIN);
-      ctxt.set_exported_decls_builder(corp.get_exported_decls_builder().get());
-
-      handle_version_attribute(reader, corp);
-
-      xml::xml_char_sptr path_str = XML_READER_GET_ATTRIBUTE(reader, "path");
-      string path;
-
-      if (path_str)
-	{
-	  path = reinterpret_cast<char*>(path_str.get());
-	  corp.set_path(path);
-	}
-
-      xml::xml_char_sptr architecture_str =
-	XML_READER_GET_ATTRIBUTE(reader, "architecture");
-      if (architecture_str)
-	corp.set_architecture_name
-	  (reinterpret_cast<char*>(architecture_str.get()));
-
-      xml::xml_char_sptr soname_str =
-	XML_READER_GET_ATTRIBUTE(reader, "soname");
-      string soname;
-
-      if (soname_str)
-	{
-	  soname = reinterpret_cast<char*>(soname_str.get());
-	  corp.set_soname(soname);
-	}
-
-      // Apply suppression specifications here to honour:
-      //
-      //   [suppress_file]
-      //     (soname_regexp
-      //      |soname_not_regexp
-      //      |file_name_regexp
-      //      |file_name_not_regexp) = <soname-or-file-name>
-      if ((!soname.empty() || !path.empty())
-	  && ctxt.corpus_is_suppressed_by_soname_or_filename(soname, path))
-	return nil;
-
-      node = xmlTextReaderExpand(reader.get());
-      if (!node)
-	return nil;
-
-      call_reader_next = true;
-    }
-  else
-    {
-      ctxt.set_corpus(std::make_shared<corpus>(ctxt.get_environment(), ""));
-#ifdef WITH_DEBUG_SELF_COMPARISON
-      if (ctxt.get_environment()->self_comparison_debug_is_on())
-	ctxt.get_environment()->
-	  set_self_comparison_debug_input(ctxt.get_corpus());
-#endif
-
-      if (!ctxt.get_corpus_group())
-	ctxt.clear_per_corpus_data();
-
-      corpus& corp = *ctxt.get_corpus();
-      corp.set_origin(corpus::NATIVE_XML_ORIGIN);
-
-      ctxt.set_exported_decls_builder(corp.get_exported_decls_builder().get());
-
-      xml::xml_char_sptr path_str = XML_NODE_GET_ATTRIBUTE(node, "path");
-      if (path_str)
-	corp.set_path(reinterpret_cast<char*>(path_str.get()));
-
-      xml::xml_char_sptr architecture_str =
-	XML_NODE_GET_ATTRIBUTE(node, "architecture");
-      if (architecture_str)
-	corp.set_architecture_name
-	  (reinterpret_cast<char*>(architecture_str.get()));
-
-      xml::xml_char_sptr soname_str =
-	XML_NODE_GET_ATTRIBUTE(node, "soname");
-      if (soname_str)
-	corp.set_soname(reinterpret_cast<char*>(soname_str.get()));
-    }
-
-  // If the corpus element node has children nodes, make
-  // ctxt.get_corpus_node() returns the first child element node of
-  // the corpus element that *needs* to be processed.
-  if (node->children)
-    {
-      xmlNodePtr n = xmlFirstElementChild(node);
-      ctxt.set_corpus_node(n);
-    }
-
-  corpus& corp = *ctxt.get_corpus();
-
-  walk_xml_node_to_map_type_ids(ctxt, node);
-
-  // Read the needed element
-  vector<string> needed;
-  read_elf_needed_from_input(ctxt, needed);
-  if (!needed.empty())
-    corp.set_needed(needed);
-
-  string_elf_symbols_map_sptr fn_sym_db, var_sym_db;
-
-  // Read the symbol databases.
-  read_symbol_db_from_input(ctxt, fn_sym_db, var_sym_db);
-  // Note that it's possible that both fn_sym_db and var_sym_db are nil,
-  // due to potential suppression specifications.  That's fine.
-  corp.set_symtab(symtab_reader::symtab::load(fn_sym_db, var_sym_db));
-
-  ctxt.get_environment()->canonicalization_is_done(false);
-
-  // Read the translation units.
-  while (read_translation_unit_from_input(ctxt))
-    ;
-
-  if (ctxt.tracking_non_reachable_types())
-    {
-      bool is_tracking_non_reachable_types = false;
-      read_tracking_non_reachable_types(node, is_tracking_non_reachable_types);
-
-      ABG_ASSERT
-	(corp.recording_types_reachable_from_public_interface_supported()
-	 == is_tracking_non_reachable_types);
-    }
-
-
-  ctxt.perform_late_type_canonicalizing();
-
-  ctxt.get_environment()->canonicalization_is_done(true);
-
-  if (call_reader_next)
-    {
-      // This is the necessary counter-part of the xmlTextReaderExpand()
-      // call at the beginning of the function.
-      xmlTextReaderNext(reader.get());
-      // The call above invalidates the xml node returned by
-      // xmlTextReaderExpand, which is can still be accessed via
-      // ctxt.set_corpus_node.
-      ctxt.set_corpus_node(0);
-    }
-  else
-    {
-      node = ctxt.get_corpus_node();
-      node = xmlNextElementSibling(node);
-      if (!node)
-	{
-	  node = ctxt.get_corpus_node();
-	  if (node)
-	    node = xmlNextElementSibling(node->parent);
-	}
-      ctxt.set_corpus_node(node);
-    }
-
-  return ctxt.get_corpus();
-}
-
 /// Parse the input XML document containing an ABI corpus group,
 /// represented by an 'abi-corpus-group' element node, associated to
 /// the current context.
 ///
-/// @param ctxt the current input context.
+/// @param rdr the current input context.
 ///
 /// @return the corpus group resulting from the parsing
 corpus_group_sptr
-read_corpus_group_from_input(read_context& ctxt)
+read_corpus_group_from_input(fe_iface& iface)
 {
   corpus_group_sptr nil;
 
-  xml::reader_sptr reader = ctxt.get_reader();
+  abixml_reader::reader& rdr = dynamic_cast<abixml_reader::reader&>(iface);
+  xml::reader_sptr reader = rdr.get_libxml_reader();
   if (!reader)
     return nil;
 
@@ -2234,21 +2081,21 @@ read_corpus_group_from_input(read_context& ctxt)
   int status = 1;
   while (status == 1
 	 && XML_READER_GET_NODE_TYPE(reader) != XML_READER_TYPE_ELEMENT)
-    status = advance_cursor (ctxt);
+    status = advance_cursor (rdr);
 
   if (status != 1 || !xmlStrEqual (XML_READER_GET_NODE_NAME(reader).get(),
 				   BAD_CAST("abi-corpus-group")))
     return nil;
 
-  if (!ctxt.get_corpus_group())
+  if (!rdr.corpus_group())
     {
-      corpus_group_sptr g(new corpus_group(ctxt.get_environment(),
-					   ctxt.get_path()));
+      corpus_group_sptr g(new corpus_group(rdr.get_environment(),
+					   rdr.get_path()));
       g->set_origin(corpus::NATIVE_XML_ORIGIN);
-      ctxt.set_corpus_group(g);
+      rdr.corpus_group(g);
     }
 
-  corpus_group_sptr group = ctxt.get_corpus_group();
+  corpus_group_sptr group = rdr.corpus_group();
 
   handle_version_attribute(reader, *group);
 
@@ -2261,15 +2108,16 @@ read_corpus_group_from_input(read_context& ctxt)
     return nil;
 
   node = xmlFirstElementChild(node);
-  ctxt.set_corpus_node(node);
+  rdr.set_corpus_node(node);
 
   corpus_sptr corp;
-  while ((corp = read_corpus_from_input(ctxt)))
-    ctxt.get_corpus_group()->add_corpus(corp);
+  fe_iface::status sts;
+  while ((corp = rdr.read_corpus(sts)))
+    rdr.corpus_group()->add_corpus(corp);
 
   xmlTextReaderNext(reader.get());
 
-  return ctxt.get_corpus_group();
+  return rdr.corpus_group();
 }
 
 /// De-serialize an ABI corpus group from an input XML document which
@@ -2285,11 +2133,11 @@ read_corpus_group_from_input(read_context& ctxt)
 /// @return the resulting corpus group de-serialized from the parsing.
 /// This is non-null iff the parsing resulted in a valid corpus group.
 corpus_group_sptr
-read_corpus_group_from_native_xml(std::istream* in,
-				  environment*  env)
+read_corpus_group_from_abixml(std::istream* in,
+			      environment&  env)
 {
-  read_context_sptr read_ctxt = create_native_xml_read_context(in, env);
-  return read_corpus_group_from_input(*read_ctxt);
+  fe_iface_sptr rdr = create_abixml_reader(in, env);
+  return read_corpus_group_from_input(*rdr);
 }
 
 /// De-serialize an ABI corpus group from an XML document file which
@@ -2307,11 +2155,11 @@ read_corpus_group_from_native_xml(std::istream* in,
 /// This is non-null if the parsing successfully resulted in a corpus
 /// group.
 corpus_group_sptr
-read_corpus_group_from_native_xml_file(const string& path,
-				       environment*  env)
+read_corpus_group_from_abixml_file(const string& path,
+				   environment&  env)
 {
-    read_context_sptr read_ctxt = create_native_xml_read_context(path, env);
-    corpus_group_sptr group = read_corpus_group_from_input(*read_ctxt);
+    fe_iface_sptr rdr = create_abixml_reader(path, env);
+    corpus_group_sptr group = read_corpus_group_from_input(*rdr);
     return group;
 }
 
@@ -2326,13 +2174,13 @@ read_corpus_group_from_native_xml_file(const string& path,
 /// successful completion, or nil.
 translation_unit_sptr
 read_translation_unit_from_file(const string&	input_file,
-				environment*	env)
+				environment&	env)
 {
-  read_context ctxt(xml::new_reader_from_file(input_file), env);
-  translation_unit_sptr tu = read_translation_unit_from_input(ctxt);
-  ctxt.get_environment()->canonicalization_is_done(false);
-  ctxt.perform_late_type_canonicalizing();
-  ctxt.get_environment()->canonicalization_is_done(true);
+  reader rdr(xml::new_reader_from_file(input_file), env);
+  translation_unit_sptr tu = read_translation_unit_from_input(rdr);
+  env.canonicalization_is_done(false);
+  rdr.perform_late_type_canonicalizing();
+  env.canonicalization_is_done(true);
   return tu;
 }
 
@@ -2348,30 +2196,31 @@ read_translation_unit_from_file(const string&	input_file,
 /// successful completion, or nil.
 translation_unit_sptr
 read_translation_unit_from_buffer(const string&	buffer,
-				  environment*		env)
+				  environment&	env)
 {
-  read_context ctxt(xml::new_reader_from_buffer(buffer), env);
-  translation_unit_sptr tu = read_translation_unit_from_input(ctxt);
-  ctxt.get_environment()->canonicalization_is_done(false);
-  ctxt.perform_late_type_canonicalizing();
-  ctxt.get_environment()->canonicalization_is_done(true);
+  reader rdr(xml::new_reader_from_buffer(buffer), env);
+  translation_unit_sptr tu = read_translation_unit_from_input(rdr);
+  env.canonicalization_is_done(false);
+  rdr.perform_late_type_canonicalizing();
+  env.canonicalization_is_done(true);
   return tu;
 }
 
 /// Parse a translation unit from an abixml input from a given
 /// context.
 ///
-/// @param ctxt the @ref read_context to consider.
+/// @param rdr the @ref reader to consider.
 ///
 /// @return the constructed @ref translation_unit from the content of
 /// the input abixml.
 translation_unit_sptr
-read_translation_unit(read_context& ctxt)
+read_translation_unit(fe_iface& iface)
 {
-  translation_unit_sptr tu = read_translation_unit_from_input(ctxt);
-  ctxt.get_environment()->canonicalization_is_done(false);
-  ctxt.perform_late_type_canonicalizing();
-  ctxt.get_environment()->canonicalization_is_done(true);
+  abixml_reader::reader& rdr = dynamic_cast<abixml_reader::reader&>(iface);
+  translation_unit_sptr tu = read_translation_unit_from_input(rdr);
+  rdr.options().env.canonicalization_is_done(false);
+  rdr.perform_late_type_canonicalizing();
+  rdr.options().env.canonicalization_is_done(true);
   return tu;
 }
 
@@ -2380,51 +2229,51 @@ read_translation_unit(read_context& ctxt)
 /// The result of the "handling" is to build the representation of the
 /// xml node and tied it to the current translation unit.
 ///
-/// @param ctxt the current parsing context.
+/// @param rdr the current parsing context.
 ///
 /// @return true upon successful completion, false otherwise.
 static type_or_decl_base_sptr
-handle_element_node(read_context& ctxt, xmlNodePtr node,
+handle_element_node(reader& rdr, xmlNodePtr node,
 		    bool add_to_current_scope)
 {
   type_or_decl_base_sptr decl;
   if (!node)
     return decl;
 
-  ((decl = handle_namespace_decl(ctxt, node, add_to_current_scope))
-   ||(decl = handle_type_decl(ctxt, node, add_to_current_scope))
-   ||(decl = handle_qualified_type_decl(ctxt, node,
+  ((decl = handle_namespace_decl(rdr, node, add_to_current_scope))
+   ||(decl = handle_type_decl(rdr, node, add_to_current_scope))
+   ||(decl = handle_qualified_type_decl(rdr, node,
 					add_to_current_scope))
-   ||(decl = handle_pointer_type_def(ctxt, node,
+   ||(decl = handle_pointer_type_def(rdr, node,
 				     add_to_current_scope))
-   || (decl = handle_reference_type_def(ctxt, node, add_to_current_scope))
-   || (decl = handle_function_type(ctxt, node, add_to_current_scope))
-   || (decl = handle_array_type_def(ctxt, node, add_to_current_scope))
-   || (decl = handle_enum_type_decl(ctxt, node,
+   || (decl = handle_reference_type_def(rdr, node, add_to_current_scope))
+   || (decl = handle_function_type(rdr, node, add_to_current_scope))
+   || (decl = handle_array_type_def(rdr, node, add_to_current_scope))
+   || (decl = handle_enum_type_decl(rdr, node,
 				    add_to_current_scope))
-   || (decl = handle_typedef_decl(ctxt, node,
+   || (decl = handle_typedef_decl(rdr, node,
 				  add_to_current_scope))
-   || (decl = handle_var_decl(ctxt, node,
+   || (decl = handle_var_decl(rdr, node,
 			      add_to_current_scope))
-   || (decl = handle_function_decl(ctxt, node,
+   || (decl = handle_function_decl(rdr, node,
 				   add_to_current_scope))
-   || (decl = handle_class_decl(ctxt, node,
+   || (decl = handle_class_decl(rdr, node,
 				add_to_current_scope))
-   || (decl = handle_union_decl(ctxt, node,
+   || (decl = handle_union_decl(rdr, node,
 				add_to_current_scope))
-   || (decl = handle_function_tdecl(ctxt, node,
+   || (decl = handle_function_tdecl(rdr, node,
 				    add_to_current_scope))
-   || (decl = handle_class_tdecl(ctxt, node,
+   || (decl = handle_class_tdecl(rdr, node,
 				 add_to_current_scope)));
 
   // If the user wants us to track non-reachable types, then read the
   // 'is-non-reachable-type' attribute on type elements and record
   // reachable types accordingly.
-  if (ctxt.tracking_non_reachable_types())
+  if (rdr.tracking_non_reachable_types())
     {
       if (type_base_sptr t = is_type(decl))
 	{
-	  corpus_sptr abi = ctxt.get_corpus();
+	  corpus_sptr abi = rdr.corpus();
 	  ABG_ASSERT(abi);
 	  bool is_non_reachable_type = false;
 	  read_is_non_reachable_type(node, is_non_reachable_type);
@@ -2438,13 +2287,13 @@ handle_element_node(read_context& ctxt, xmlNodePtr node,
 
 /// Parses location attributes on an xmlNodePtr.
 ///
-///@param ctxt the current parsing context
+///@param rdr the current parsing context
 ///
 ///@param loc the resulting location.
 ///
 /// @return true upon sucessful parsing, false otherwise.
 static bool
-read_location(const read_context&	ctxt,
+read_location(const reader&	rdr,
 	      xmlNodePtr		node,
 	      location&		loc)
 {
@@ -2455,17 +2304,17 @@ read_location(const read_context&	ctxt,
     file_path = CHAR_STR(f);
 
   if (file_path.empty())
-    return read_artificial_location(ctxt, node, loc);
+    return read_artificial_location(rdr, node, loc);
 
   if (xml_char_sptr l = xml::build_sptr(xmlGetProp(node, BAD_CAST("line"))))
     line = atoi(CHAR_STR(l));
   else
-    return read_artificial_location(ctxt, node, loc);
+    return read_artificial_location(rdr, node, loc);
 
   if (xml_char_sptr c = xml::build_sptr(xmlGetProp(node, BAD_CAST("column"))))
     column = atoi(CHAR_STR(c));
 
-  read_context& c = const_cast<read_context&>(ctxt);
+  reader& c = const_cast<reader&>(rdr);
   loc = c.get_translation_unit()->get_loc_mgr().create_new_location(file_path,
 								    line,
 								    column);
@@ -2477,13 +2326,13 @@ read_location(const read_context&	ctxt,
 /// The artificial location is the line number of the xmlNode as well
 /// as the URI of the node.
 ///
-///@param ctxt the current parsing context
+///@param rdr the current parsing context
 ///
 ///@param loc the resulting location.
 ///
 /// @return true upon sucessful parsing, false otherwise.
 static bool
-read_artificial_location(const read_context& ctxt,
+read_artificial_location(const reader& rdr,
 			 xmlNodePtr node,
 			 location& loc)
 {
@@ -2498,7 +2347,7 @@ read_artificial_location(const read_context& ctxt,
    if (node->doc)
        file_path = reinterpret_cast<const char*>(node->doc->URL);
 
-   read_context& c = const_cast<read_context&>(ctxt);
+   reader& c = const_cast<reader&>(rdr);
    loc =
      c.get_translation_unit()->get_loc_mgr().create_new_location(file_path,
 								 line, column);
@@ -2514,7 +2363,7 @@ read_artificial_location(const read_context& ctxt,
 /// The function sets the artificial location only if the artifact
 /// doesn"t already have one.
 ///
-///@param ctxt the current parsing context
+///@param rdr the current parsing context
 ///
 ///@param node the XML node to consider.
 ///
@@ -2522,14 +2371,14 @@ read_artificial_location(const read_context& ctxt,
 ///
 /// @return true iff the location was set on the artifact.
 static bool
-maybe_set_artificial_location(const read_context& ctxt,
+maybe_set_artificial_location(const reader& rdr,
 			      xmlNodePtr node,
 			      type_or_decl_base_sptr artefact)
 {
   if (artefact && !artefact->has_artificial_location())
     {
       location l;
-      if (read_artificial_location(ctxt, node, l))
+      if (read_artificial_location(rdr, node, l))
 	{
 	  artefact->set_artificial_location(l);
 	  return true;
@@ -3052,12 +2901,12 @@ maybe_map_type_with_type_id(const type_base_sptr& t,
   if (!t)
     return false;
 
-  environment *env = t->get_environment();
-  if (!env->self_comparison_debug_is_on()
+  const environment& env = t->get_environment();
+  if (!env.self_comparison_debug_is_on()
       || is_non_canonicalized_type(t.get()))
     return false;
 
-  env->get_pointer_type_id_map()[reinterpret_cast<uintptr_t>(t.get())] =
+  env.get_pointer_type_id_map()[reinterpret_cast<uintptr_t>(t.get())] =
     type_id;
 
   return true;
@@ -3083,8 +2932,8 @@ maybe_map_type_with_type_id(const type_base_sptr& t,
   if (!t)
     return false;
 
-  environment *env = t->get_environment();
-  if (!env->self_comparison_debug_is_on()
+  const environment&env = t->get_environment();
+  if (!env.self_comparison_debug_is_on()
       || is_non_canonicalized_type(t.get()))
     return false;
 
@@ -3100,13 +2949,13 @@ maybe_map_type_with_type_id(const type_base_sptr& t,
 /// Set the naming typedef to a given decl depending on the content of
 /// the "naming-typedef-id" property of its descriptive XML element.
 ///
-/// @param ctxt the current read context.
+/// @param rdr the current ABIXML reader.
 ///
 /// @param node the XML node to read from.
 ///
 /// @param decl the decl to set the naming typedef to.
 static void
-maybe_set_naming_typedef(read_context&		ctxt,
+maybe_set_naming_typedef(reader&		rdr,
 			 xmlNodePtr		node,
 			 const decl_base_sptr&	decl)
 {
@@ -3115,7 +2964,7 @@ maybe_set_naming_typedef(read_context&		ctxt,
   if (!naming_typedef_id.empty())
     {
       typedef_decl_sptr naming_typedef =
-	is_typedef(ctxt.build_or_get_type_decl(naming_typedef_id, true));
+	is_typedef(rdr.build_or_get_type_decl(naming_typedef_id, true));
       ABG_ASSERT(naming_typedef);
       decl->set_naming_typedef(naming_typedef);
     }
@@ -3126,7 +2975,7 @@ maybe_set_naming_typedef(read_context&		ctxt,
 /// content of the namespace and builds the proper IR nodes
 /// accordingly.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the ABIXML reader to use.
 ///
 /// @param node the XML node to consider.  It must constain the
 /// content of the namespace, that is, children XML nodes representing
@@ -3137,7 +2986,7 @@ maybe_set_naming_typedef(read_context&		ctxt,
 ///
 /// @return a pointer to the the resulting @ref namespace_decl.
 static namespace_decl_sptr
-build_namespace_decl(read_context&	ctxt,
+build_namespace_decl(reader&	rdr,
 		     const xmlNodePtr	node,
 		     bool		add_to_current_scope)
 {
@@ -3145,7 +2994,7 @@ build_namespace_decl(read_context&	ctxt,
   if (!node || !xmlStrEqual(node->name, BAD_CAST("namespace-decl")))
     return nil;
 
-  if (decl_base_sptr d = ctxt.get_decl_for_xml_node(node))
+  if (decl_base_sptr d = rdr.get_decl_for_xml_node(node))
     {
       namespace_decl_sptr result = dynamic_pointer_cast<namespace_decl>(d);
       ABG_ASSERT(result);
@@ -3157,20 +3006,20 @@ build_namespace_decl(read_context&	ctxt,
     name = xml::unescape_xml_string(CHAR_STR(s));
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
 
-  const environment* env = ctxt.get_environment();
+  const environment& env = rdr.get_environment();
   namespace_decl_sptr decl(new namespace_decl(env, name, loc));
-  maybe_set_artificial_location(ctxt, node, decl);
-  ctxt.push_decl_to_current_scope(decl, add_to_current_scope);
-  ctxt.map_xml_node_to_decl(node, decl);
+  maybe_set_artificial_location(rdr, node, decl);
+  rdr.push_decl_to_current_scope(decl, add_to_current_scope);
+  rdr.map_xml_node_to_decl(node, decl);
 
   for (xmlNodePtr n = xmlFirstElementChild(node);
        n;
        n = xmlNextElementSibling(n))
-    handle_element_node(ctxt, n, /*add_to_current_scope=*/true);
+    handle_element_node(rdr, n, /*add_to_current_scope=*/true);
 
-  ctxt.pop_scope_or_abort(decl);
+  rdr.pop_scope_or_abort(decl);
 
   return decl;
 }
@@ -3178,7 +3027,7 @@ build_namespace_decl(read_context&	ctxt,
 /// Build an instance of @ref elf_symbol from an XML element node
 /// which name is 'elf-symbol'.
 ///
-/// @param ctxt the context used for reading the XML input.
+/// @param rdr the context used for reading the XML input.
 ///
 /// @param node the XML node to read.
 ///
@@ -3187,7 +3036,7 @@ build_namespace_decl(read_context&	ctxt,
 ///
 /// @return the @ref elf_symbol built, or nil if it couldn't be built.
 static elf_symbol_sptr
-build_elf_symbol(read_context& ctxt, const xmlNodePtr node,
+build_elf_symbol(reader& rdr, const xmlNodePtr node,
 		 bool drop_if_suppressed)
 {
   elf_symbol_sptr nil;
@@ -3251,11 +3100,11 @@ build_elf_symbol(read_context& ctxt, const xmlNodePtr node,
 
   elf_symbol::version version(version_string, is_default_version);
 
-  const bool is_suppressed = suppr::is_elf_symbol_suppressed(ctxt, name, type);
+  const bool is_suppressed = suppr::is_elf_symbol_suppressed(rdr, name, type);
   if (drop_if_suppressed && is_suppressed)
     return elf_symbol_sptr();
 
-  const environment* env = ctxt.get_environment();
+  const environment& env = rdr.get_environment();
   elf_symbol_sptr e = elf_symbol::create(env, /*index=*/0,
 					 size, name, type, binding,
 					 is_defined, is_common,
@@ -3281,7 +3130,7 @@ build_elf_symbol(read_context& ctxt, const xmlNodePtr node,
 /// present in the symbol db of the corpus associated to the current
 /// context.
 ///
-/// @param ctxt the current context to consider.
+/// @param rdr the current context to consider.
 ///
 /// @param node the xml element node to consider.
 ///
@@ -3290,7 +3139,7 @@ build_elf_symbol(read_context& ctxt, const xmlNodePtr node,
 ///
 /// @return a shared pointer the resutling elf_symbol.
 static elf_symbol_sptr
-build_elf_symbol_from_reference(read_context& ctxt, const xmlNodePtr node)
+build_elf_symbol_from_reference(reader& rdr, const xmlNodePtr node)
 {
   elf_symbol_sptr nil;
 
@@ -3310,7 +3159,7 @@ build_elf_symbol_from_reference(read_context& ctxt, const xmlNodePtr node)
 	return nil;
 
       const elf_symbols& symbols =
-	  ctxt.get_corpus()->get_symtab()->lookup_symbol(name);
+	  rdr.corpus()->get_symtab()->lookup_symbol(name);
 
       for (const auto& symbol : symbols)
 	if (symbol->get_id_string() == sym_id)
@@ -3324,7 +3173,7 @@ build_elf_symbol_from_reference(read_context& ctxt, const xmlNodePtr node)
 /// element representing either a function symbols data base, or a
 /// variable symbols database.
 ///
-/// @param ctxt the context to take in account.
+/// @param rdr the context to take in account.
 ///
 /// @param node the XML node to consider.
 ///
@@ -3332,7 +3181,7 @@ build_elf_symbol_from_reference(read_context& ctxt, const xmlNodePtr node)
 /// data base, false if we should look for a variable symbols data
 /// base.
 static string_elf_symbols_map_sptr
-build_elf_symbol_db(read_context& ctxt,
+build_elf_symbol_db(reader& rdr,
 		    const xmlNodePtr node,
 		    bool function_syms)
 {
@@ -3350,7 +3199,7 @@ build_elf_symbol_db(read_context& ctxt,
       && !xmlStrEqual(node->name, BAD_CAST("elf-variable-symbols")))
     return nil;
 
-  ctxt.set_corpus_node(node);
+  rdr.set_corpus_node(node);
 
   typedef std::unordered_map<xmlNodePtr, elf_symbol_sptr>
     xml_node_ptr_elf_symbol_sptr_map_type;
@@ -3360,7 +3209,7 @@ build_elf_symbol_db(read_context& ctxt,
   for (xmlNodePtr n = xmlFirstElementChild(node);
        n;
        n = xmlNextElementSibling(n))
-    if ((sym = build_elf_symbol(ctxt, n, /*drop_if_suppress=*/false)))
+    if ((sym = build_elf_symbol(rdr, n, /*drop_if_suppress=*/false)))
       {
 	id_sym_map[sym->get_id_string()] = sym;
 	xml_node_ptr_elf_symbol_map[n] = sym;
@@ -3410,19 +3259,17 @@ build_elf_symbol_db(read_context& ctxt,
 
 /// Build a function parameter from a 'parameter' xml element node.
 ///
-/// @param ctxt the contexte of the xml parsing.
+/// @param rdr the contexte of the xml parsing.
 ///
 /// @param node the xml 'parameter' element node to de-serialize from.
 static shared_ptr<function_decl::parameter>
-build_function_parameter(read_context& ctxt, const xmlNodePtr node)
+build_function_parameter(reader& rdr, const xmlNodePtr node)
 {
   shared_ptr<function_decl::parameter> nil;
 
   if (!node || !xmlStrEqual(node->name, BAD_CAST("parameter")))
     return nil;
 
-  ABG_ASSERT(ctxt.get_environment());
-
   bool is_variadic = false;
   string is_variadic_str;
   if (xml_char_sptr s =
@@ -3441,21 +3288,20 @@ build_function_parameter(read_context& ctxt, const xmlNodePtr node)
 
   type_base_sptr type;
   if (is_variadic)
-    type = ctxt.get_environment()->get_variadic_parameter_type();
+    type = rdr.get_environment().get_variadic_parameter_type();
   else
     {
       ABG_ASSERT(!type_id.empty());
-      type = ctxt.build_or_get_type_decl(type_id, true);
+      type = rdr.build_or_get_type_decl(type_id, true);
     }
   ABG_ASSERT(type);
-  ABG_ASSERT(type->get_environment() == ctxt.get_environment());
 
   string name;
   if (xml_char_sptr a = xml::build_sptr(xmlGetProp(node, BAD_CAST("name"))))
     name = CHAR_STR(a);
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
 
   function_decl::parameter_sptr p
     (new function_decl::parameter(type, name, loc,
@@ -3466,7 +3312,7 @@ build_function_parameter(read_context& ctxt, const xmlNodePtr node)
 
 /// Build a function_decl from a 'function-decl' xml node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to build the function_decl from.
 ///
@@ -3483,7 +3329,7 @@ build_function_parameter(read_context& ctxt, const xmlNodePtr node)
 /// @return a pointer to a newly created function_decl upon successful
 /// completion, a null pointer otherwise.
 static function_decl_sptr
-build_function_decl(read_context&	ctxt,
+build_function_decl(reader&	rdr,
 		    const xmlNodePtr	node,
 		    class_or_union_sptr as_method_decl,
 		    bool		add_to_current_scope)
@@ -3512,16 +3358,16 @@ build_function_decl(read_context&	ctxt,
   decl_base::binding bind = decl_base::BINDING_NONE;
   read_binding(node, bind);
 
-  size_t size = ctxt.get_translation_unit()->get_address_size(), align = 0;
+  size_t size = rdr.get_translation_unit()->get_address_size(), align = 0;
   read_size_and_alignment(node, size, align);
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
+
+  const environment& env = rdr.get_environment();
 
-  environment* env = ctxt.get_environment();
-  ABG_ASSERT(env);
   std::vector<function_decl::parameter_sptr> parms;
-  type_base_sptr return_type = env->get_void_type();
+  type_base_sptr return_type = env.get_void_type();
 
   for (xmlNodePtr n = xmlFirstElementChild(node);
        n ;
@@ -3530,7 +3376,7 @@ build_function_decl(read_context&	ctxt,
       if (xmlStrEqual(n->name, BAD_CAST("parameter")))
 	{
 	  if (function_decl::parameter_sptr p =
-	      build_function_parameter(ctxt, n))
+	      build_function_parameter(rdr, n))
 	    parms.push_back(p);
 	}
       else if (xmlStrEqual(n->name, BAD_CAST("return")))
@@ -3540,7 +3386,7 @@ build_function_decl(read_context&	ctxt,
 	      xml::build_sptr(xmlGetProp(n, BAD_CAST("type-id"))))
 	    type_id = CHAR_STR(s);
 	  if (!type_id.empty())
-	    return_type = ctxt.build_or_get_type_decl(type_id, true);
+	    return_type = rdr.build_or_get_type_decl(type_id, true);
 	}
     }
 
@@ -3564,22 +3410,22 @@ build_function_decl(read_context&	ctxt,
 						 mangled_name, vis,
 						 bind));
 
-  maybe_set_artificial_location(ctxt, node, fn_decl);
-  ctxt.push_decl_to_current_scope(fn_decl, add_to_current_scope);
-  RECORD_ARTIFACTS_AS_USED_IN_FN_DECL(ctxt, fn_decl);
+  maybe_set_artificial_location(rdr, node, fn_decl);
+  rdr.push_decl_to_current_scope(fn_decl, add_to_current_scope);
+  RECORD_ARTIFACTS_AS_USED_IN_FN_DECL(rdr, fn_decl);
 
-  elf_symbol_sptr sym = build_elf_symbol_from_reference(ctxt, node);
+  elf_symbol_sptr sym = build_elf_symbol_from_reference(rdr, node);
   if (sym)
     fn_decl->set_symbol(sym);
 
   if (fn_decl->get_symbol() && fn_decl->get_symbol()->is_public())
     fn_decl->set_is_in_public_symbol_table(true);
 
-  ctxt.get_translation_unit()->bind_function_type_life_time(fn_type);
+  rdr.get_translation_unit()->bind_function_type_life_time(fn_type);
 
-  ctxt.maybe_canonicalize_type(fn_type, !add_to_current_scope);
+  rdr.maybe_canonicalize_type(fn_type, !add_to_current_scope);
 
-  ctxt.maybe_add_fn_to_exported_decls(fn_decl.get());
+  rdr.maybe_add_fn_to_exported_decls(fn_decl.get());
 
   return fn_decl;
 }
@@ -3588,7 +3434,7 @@ build_function_decl(read_context&	ctxt,
 /// been suppressed by a suppression specification that is in the
 /// context.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to build the function_decl from.
 ///
@@ -3606,20 +3452,20 @@ build_function_decl(read_context&	ctxt,
 /// completion.  If the function was suppressed by a suppression
 /// specification then returns nil.
 static function_decl_sptr
-build_function_decl_if_not_suppressed(read_context&	ctxt,
+build_function_decl_if_not_suppressed(reader&	rdr,
 				      const xmlNodePtr	node,
 				      class_or_union_sptr as_method_decl,
 				      bool		add_to_current_scope)
 {
     function_decl_sptr fn;
 
-  if (function_is_suppressed(ctxt, node))
+  if (function_is_suppressed(rdr, node))
     // The function was suppressed by at least one suppression
-    // specification associated to the current read context.  So
+    // specification associated to the current ABIXML reader.  So
     // don't build any IR for it.
     ;
   else
-    fn = build_function_decl(ctxt, node, as_method_decl,
+    fn = build_function_decl(rdr, node, as_method_decl,
 			     add_to_current_scope);
   return fn;
 }
@@ -3628,7 +3474,7 @@ build_function_decl_if_not_suppressed(read_context&	ctxt,
 /// suppressed by any of the suppression specifications associated to
 /// a given context of native xml reading.
 ///
-/// @param ctxt the native xml reading context of interest.
+/// @param rdr the native xml reading context of interest.
 ///
 /// @param note the XML node that represents the fucntion.
 /// match.
@@ -3636,7 +3482,7 @@ build_function_decl_if_not_suppressed(read_context&	ctxt,
 /// @return true iff at least one function specification matches the
 /// function denoted by the node @p node.
 static bool
-function_is_suppressed(const read_context& ctxt, xmlNodePtr node)
+function_is_suppressed(const reader& rdr, xmlNodePtr node)
 {
   string fname;
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "name"))
@@ -3646,49 +3492,49 @@ function_is_suppressed(const read_context& ctxt, xmlNodePtr node)
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "mangled-name"))
     flinkage_name = xml::unescape_xml_string(CHAR_STR(s));
 
-  scope_decl* scope = ctxt.get_cur_scope();
+  scope_decl* scope = rdr.get_cur_scope();
 
   string qualified_name = build_qualified_name(scope, fname);
 
-  return suppr::function_is_suppressed(ctxt, qualified_name, flinkage_name);
+  return suppr::is_function_suppressed(rdr, qualified_name, flinkage_name);
 }
 
 /// Test if a type denoted by its name, context and location is
 /// suppressed by the suppression specifications that are associated
-/// to a given read context.
+/// to a given ABIXML reader.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the ABIXML reader to consider.
 ///
 /// @param note the XML node that represents the type.
 ///
 /// @return true iff the type designated by @p node is suppressed by
 ///  at least of suppression specifications associated to the current
-///  read context.
+///  ABIXML reader.
 static bool
-type_is_suppressed(const read_context& ctxt, xmlNodePtr node)
+type_is_suppressed(const reader& rdr, xmlNodePtr node)
 {
   string type_name;
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "name"))
     type_name = xml::unescape_xml_string(CHAR_STR(s));
 
   location type_location;
-  read_location(ctxt, node, type_location);
+  read_location(rdr, node, type_location);
 
-  scope_decl* scope = ctxt.get_cur_scope();
+  scope_decl* scope = rdr.get_cur_scope();
 
   string qualified_name = build_qualified_name(scope, type_name);
 
   bool type_is_private = false;
-  return suppr::type_is_suppressed(ctxt, qualified_name, type_location,
+  return suppr::is_type_suppressed(rdr, qualified_name, type_location,
 				   type_is_private,
 				   /*require_drop_property=*/true);
 }
 
 /// Build a @ref var_decl out of a an XML node that describes it iff
 /// the variable denoted by the XML node is not suppressed by a
-/// suppression specification associated to the current read context.
+/// suppression specification associated to the current ABIXML reader.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the ABIXML reader to use.
 ///
 /// @param node the XML node for the variable to consider.
 ///
@@ -3697,26 +3543,26 @@ type_is_suppressed(const read_context& ctxt, xmlNodePtr node)
 ///
 /// @return true iff the @ref var_decl was built.
 static var_decl_sptr
-build_var_decl_if_not_suppressed(read_context&		ctxt,
+build_var_decl_if_not_suppressed(reader&		rdr,
 				 const xmlNodePtr	node,
 				 bool			add_to_current_scope)
 {
   var_decl_sptr var;
-  if (!variable_is_suppressed(ctxt, node))
-    var = build_var_decl(ctxt, node, add_to_current_scope);
+  if (!variable_is_suppressed(rdr, node))
+    var = build_var_decl(rdr, node, add_to_current_scope);
   return var;
 }
 
 /// Test if a variable denoted by its XML node is suppressed by a
-/// suppression specification that is present in a given read context.
+/// suppression specification that is present in a given ABIXML reader.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the ABIXML reader to consider.
 ///
 /// @param node the XML node of the variable to consider.
 ///
 /// @return true iff the variable denoted by @p node is suppressed.
 static bool
-variable_is_suppressed(const read_context& ctxt, xmlNodePtr node)
+variable_is_suppressed(const reader& rdr, xmlNodePtr node)
 {
   string name;
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "name"))
@@ -3726,17 +3572,17 @@ variable_is_suppressed(const read_context& ctxt, xmlNodePtr node)
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "mangled-name"))
     linkage_name = xml::unescape_xml_string(CHAR_STR(s));
 
-  scope_decl* scope = ctxt.get_cur_scope();
+  scope_decl* scope = rdr.get_cur_scope();
 
   string qualified_name = build_qualified_name(scope, name);
 
-  return suppr::variable_is_suppressed(ctxt, qualified_name, linkage_name);
+  return suppr::is_variable_suppressed(rdr, qualified_name, linkage_name);
 }
 
 /// Test if a variable in a particular scope is suppressed by a
-/// suppression specification that is present in a given read context.
+/// suppression specification that is present in a given ABIXML reader.
 ///
-/// @parm ctxt the read context to consider.
+/// @parm rdr the ABIXML reader to consider.
 ///
 /// @param scope the scope of the variable to consider.
 ///
@@ -3744,25 +3590,25 @@ variable_is_suppressed(const read_context& ctxt, xmlNodePtr node)
 ///
 /// @return true iff the variable @p v is suppressed.
 static bool
-variable_is_suppressed(const read_context& ctxt,
+variable_is_suppressed(const reader& rdr,
 		       const scope_decl* scope,
 		       const var_decl& v)
 {
   string qualified_name = build_qualified_name(scope, v.get_name());
-  return suppr::variable_is_suppressed(ctxt, qualified_name,
+  return suppr::is_variable_suppressed(rdr, qualified_name,
 				       v.get_linkage_name());
 }
 
 /// Build pointer to var_decl from a 'var-decl' xml Node
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to build the var_decl from.
 ///
 /// @return a pointer to a newly built var_decl upon successful
 /// completion, a null pointer otherwise.
 static shared_ptr<var_decl>
-build_var_decl(read_context&	ctxt,
+build_var_decl(reader&	rdr,
 	       const xmlNodePtr node,
 	       bool		add_to_current_scope)
 {
@@ -3778,7 +3624,7 @@ build_var_decl(read_context&	ctxt,
   string type_id;
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "type-id"))
     type_id = CHAR_STR(s);
-  type_base_sptr underlying_type = ctxt.build_or_get_type_decl(type_id,
+  type_base_sptr underlying_type = rdr.build_or_get_type_decl(type_id,
 							       true);
   ABG_ASSERT(underlying_type);
 
@@ -3793,23 +3639,23 @@ build_var_decl(read_context&	ctxt,
   read_binding(node, bind);
 
   location locus;
-  read_location(ctxt, node, locus);
+  read_location(rdr, node, locus);
 
   var_decl_sptr decl(new var_decl(name, underlying_type,
 				  locus, mangled_name,
 				  vis, bind));
-  maybe_set_artificial_location(ctxt, node, decl);
+  maybe_set_artificial_location(rdr, node, decl);
 
-  elf_symbol_sptr sym = build_elf_symbol_from_reference(ctxt, node);
+  elf_symbol_sptr sym = build_elf_symbol_from_reference(rdr, node);
   if (sym)
     decl->set_symbol(sym);
 
-  ctxt.push_decl_to_current_scope(decl, add_to_current_scope);
+  rdr.push_decl_to_current_scope(decl, add_to_current_scope);
   if (add_to_current_scope)
     {
       // This variable is really being kept in the IR, so let's record
       // that it's using its type.
-      RECORD_ARTIFACT_AS_USED_BY(ctxt, underlying_type, decl);
+      RECORD_ARTIFACT_AS_USED_BY(rdr, underlying_type, decl);
     }
 
   if (decl->get_symbol() && decl->get_symbol()->is_public())
@@ -3820,7 +3666,7 @@ build_var_decl(read_context&	ctxt,
 
 /// Build a type_decl from a "type-decl" XML Node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the XML node to build the type_decl from.
 ///
@@ -3830,7 +3676,7 @@ build_var_decl(read_context&	ctxt,
 /// @return a pointer to type_decl upon successful completion, a null
 /// pointer otherwise.
 static shared_ptr<type_decl>
-build_type_decl(read_context&		ctxt,
+build_type_decl(reader&		rdr,
 		const xmlNodePtr	node,
 		bool			add_to_current_scope)
 {
@@ -3839,7 +3685,7 @@ build_type_decl(read_context&		ctxt,
   if (!xmlStrEqual(node->name, BAD_CAST("type-decl")))
     return nil;
 
-  if (decl_base_sptr d = ctxt.get_decl_for_xml_node(node))
+  if (decl_base_sptr d = rdr.get_decl_for_xml_node(node))
     {
       type_decl_sptr result = dynamic_pointer_cast<type_decl>(d);
       ABG_ASSERT(result);
@@ -3867,12 +3713,12 @@ build_type_decl(read_context&		ctxt,
   read_is_declaration_only(node, is_decl_only);
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
 
   bool is_anonymous = false;
   read_is_anonymous(node, is_anonymous);
 
-  if (type_base_sptr d = ctxt.get_type_decl(id))
+  if (type_base_sptr d = rdr.get_type_decl(id))
     {
       // I've seen instances of DSOs where a type_decl would appear
       // several times.  Hugh.
@@ -3885,15 +3731,15 @@ build_type_decl(read_context&		ctxt,
       return ty;
     }
 
-  const environment* env = ctxt.get_environment();
+  const environment& env = rdr.get_environment();
   type_decl_sptr decl(new type_decl(env, name, size_in_bits,
 				    alignment_in_bits, loc));
-  maybe_set_artificial_location(ctxt, node, decl);
+  maybe_set_artificial_location(rdr, node, decl);
   decl->set_is_anonymous(is_anonymous);
   decl->set_is_declaration_only(is_decl_only);
-  if (ctxt.push_and_key_type_decl(decl, id, add_to_current_scope))
+  if (rdr.push_and_key_type_decl(decl, id, add_to_current_scope))
     {
-      ctxt.map_xml_node_to_decl(node, decl);
+      rdr.map_xml_node_to_decl(node, decl);
       return decl;
     }
 
@@ -3902,7 +3748,7 @@ build_type_decl(read_context&		ctxt,
 
 /// Build a qualified_type_def from a 'qualified-type-def' xml node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to build the qualified_type_def from.
 ///
@@ -3912,7 +3758,7 @@ build_type_decl(read_context&		ctxt,
 /// @return a pointer to a newly built qualified_type_def upon
 /// successful completion, a null pointer otherwise.
 static qualified_type_def_sptr
-build_qualified_type_decl(read_context&	ctxt,
+build_qualified_type_decl(reader&	rdr,
 			  const xmlNodePtr	node,
 			  bool			add_to_current_scope)
 {
@@ -3920,7 +3766,7 @@ build_qualified_type_decl(read_context&	ctxt,
   if (!xmlStrEqual(node->name, BAD_CAST("qualified-type-def")))
     return nil;
 
-  if (decl_base_sptr d = ctxt.get_decl_for_xml_node(node))
+  if (decl_base_sptr d = rdr.get_decl_for_xml_node(node))
     {
       qualified_type_def_sptr result =
 	dynamic_pointer_cast<qualified_type_def>(d);
@@ -3935,7 +3781,7 @@ build_qualified_type_decl(read_context&	ctxt,
   ABG_ASSERT(!id.empty());
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
 
   qualified_type_def::CV cv = qualified_type_def::CV_NONE;
     string const_str;
@@ -3966,11 +3812,11 @@ build_qualified_type_decl(read_context&	ctxt,
   ABG_ASSERT(!type_id.empty());
 
   shared_ptr<type_base> underlying_type =
-    ctxt.build_or_get_type_decl(type_id, true);
+    rdr.build_or_get_type_decl(type_id, true);
   ABG_ASSERT(underlying_type);
 
   qualified_type_def_sptr decl;
-  if (type_base_sptr t = ctxt.get_type_decl(id))
+  if (type_base_sptr t = rdr.get_type_decl(id))
     {
       decl = is_qualified_type(t);
       ABG_ASSERT(decl);
@@ -3978,19 +3824,19 @@ build_qualified_type_decl(read_context&	ctxt,
   else
     {
       decl.reset(new qualified_type_def(underlying_type, cv, loc));
-      maybe_set_artificial_location(ctxt, node, decl);
-      ctxt.push_and_key_type_decl(decl, id, add_to_current_scope);
-      RECORD_ARTIFACT_AS_USED_BY(ctxt, underlying_type, decl);
+      maybe_set_artificial_location(rdr, node, decl);
+      rdr.push_and_key_type_decl(decl, id, add_to_current_scope);
+      RECORD_ARTIFACT_AS_USED_BY(rdr, underlying_type, decl);
     }
 
-  ctxt.map_xml_node_to_decl(node, decl);
+  rdr.map_xml_node_to_decl(node, decl);
 
   return decl;
 }
 
 /// Build a pointer_type_def from a 'pointer-type-def' xml node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to build the pointer_type_def from.
 ///
@@ -4000,7 +3846,7 @@ build_qualified_type_decl(read_context&	ctxt,
 /// @return a pointer to a newly built pointer_type_def upon
 /// successful completion, a null pointer otherwise.
 static pointer_type_def_sptr
-build_pointer_type_def(read_context&	ctxt,
+build_pointer_type_def(reader&	rdr,
 		       const xmlNodePtr node,
 		       bool		add_to_current_scope)
 {
@@ -4010,7 +3856,7 @@ build_pointer_type_def(read_context&	ctxt,
   if (!xmlStrEqual(node->name, BAD_CAST("pointer-type-def")))
     return nil;
 
-  if (decl_base_sptr d = ctxt.get_decl_for_xml_node(node))
+  if (decl_base_sptr d = rdr.get_decl_for_xml_node(node))
     {
       pointer_type_def_sptr result =
 	dynamic_pointer_cast<pointer_type_def>(d);
@@ -4023,7 +3869,7 @@ build_pointer_type_def(read_context&	ctxt,
     id = CHAR_STR(s);
   ABG_ASSERT(!id.empty());
 
-  if (type_base_sptr t = ctxt.get_type_decl(id))
+  if (type_base_sptr t = rdr.get_type_decl(id))
     {
       pointer_type_def_sptr result = is_pointer_type(t);
       ABG_ASSERT(result);
@@ -4034,39 +3880,39 @@ build_pointer_type_def(read_context&	ctxt,
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "type-id"))
     type_id = CHAR_STR(s);
 
-  size_t size_in_bits = ctxt.get_translation_unit()->get_address_size();
+  size_t size_in_bits = rdr.get_translation_unit()->get_address_size();
   size_t alignment_in_bits = 0;
   read_size_and_alignment(node, size_in_bits, alignment_in_bits);
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
 
   // Create the pointer type /before/ the pointed-to type.  After the
-  // creation, the type is 'keyed' using ctxt.push_and_key_type_decl.
+  // creation, the type is 'keyed' using rdr.push_and_key_type_decl.
   // This means that the type can be retrieved from its type ID.  This
   // is so that if the pointed-to type indirectly uses this pointer
   // type (via recursion) then that is made possible.
-  pointer_type_def_sptr t(new pointer_type_def(ctxt.get_environment(),
+  pointer_type_def_sptr t(new pointer_type_def(rdr.get_environment(),
 					       size_in_bits,
 					       alignment_in_bits,
 					       loc));
-  maybe_set_artificial_location(ctxt, node, t);
+  maybe_set_artificial_location(rdr, node, t);
 
-  if (ctxt.push_and_key_type_decl(t, id, add_to_current_scope))
-    ctxt.map_xml_node_to_decl(node, t);
+  if (rdr.push_and_key_type_decl(t, id, add_to_current_scope))
+    rdr.map_xml_node_to_decl(node, t);
 
   type_base_sptr pointed_to_type =
-    ctxt.build_or_get_type_decl(type_id, true);
+    rdr.build_or_get_type_decl(type_id, true);
   ABG_ASSERT(pointed_to_type);
 
   t->set_pointed_to_type(pointed_to_type);
-  RECORD_ARTIFACT_AS_USED_BY(ctxt, pointed_to_type, t);
+  RECORD_ARTIFACT_AS_USED_BY(rdr, pointed_to_type, t);
   return t;
 }
 
 /// Build a reference_type_def from a pointer to 'reference-type-def'
 /// xml node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to build the reference_type_def from.
 ///
@@ -4076,7 +3922,7 @@ build_pointer_type_def(read_context&	ctxt,
 /// @return a pointer to a newly built reference_type_def upon
 /// successful completio, a null pointer otherwise.
 static shared_ptr<reference_type_def>
-build_reference_type_def(read_context&		ctxt,
+build_reference_type_def(reader&		rdr,
 			 const xmlNodePtr	node,
 			 bool			add_to_current_scope)
 {
@@ -4085,7 +3931,7 @@ build_reference_type_def(read_context&		ctxt,
   if (!xmlStrEqual(node->name, BAD_CAST("reference-type-def")))
     return nil;
 
-  if (decl_base_sptr d = ctxt.get_decl_for_xml_node(node))
+  if (decl_base_sptr d = rdr.get_decl_for_xml_node(node))
     {
       reference_type_def_sptr result =
 	dynamic_pointer_cast<reference_type_def>(d);
@@ -4098,7 +3944,7 @@ build_reference_type_def(read_context&		ctxt,
     id = CHAR_STR(s);
   ABG_ASSERT(!id.empty());
 
-  if (type_base_sptr d = ctxt.get_type_decl(id))
+  if (type_base_sptr d = rdr.get_type_decl(id))
     {
       reference_type_def_sptr ty = is_reference_type(d);
       ABG_ASSERT(ty);
@@ -4106,13 +3952,13 @@ build_reference_type_def(read_context&		ctxt,
     }
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
   string kind;
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "kind"))
     kind = CHAR_STR(s); // this should be either "lvalue" or "rvalue".
   bool is_lvalue = kind == "lvalue";
 
-  size_t size_in_bits = ctxt.get_translation_unit()->get_address_size();
+  size_t size_in_bits = rdr.get_translation_unit()->get_address_size();
   size_t alignment_in_bits = 0;
   read_size_and_alignment(node, size_in_bits, alignment_in_bits);
 
@@ -4123,22 +3969,22 @@ build_reference_type_def(read_context&		ctxt,
 
   // Create the reference type /before/ the pointed-to type.  After
   // the creation, the type is 'keyed' using
-  // ctxt.push_and_key_type_decl.  This means that the type can be
+  // rdr.push_and_key_type_decl.  This means that the type can be
   // retrieved from its type ID.  This is so that if the pointed-to
   // type indirectly uses this reference type (via recursion) then
   // that is made possible.
-  reference_type_def_sptr t(new reference_type_def(ctxt.get_environment(),
+  reference_type_def_sptr t(new reference_type_def(rdr.get_environment(),
 						   is_lvalue, size_in_bits,
 						   alignment_in_bits, loc));
-  maybe_set_artificial_location(ctxt, node, t);
-  if (ctxt.push_and_key_type_decl(t, id, add_to_current_scope))
-    ctxt.map_xml_node_to_decl(node, t);
+  maybe_set_artificial_location(rdr, node, t);
+  if (rdr.push_and_key_type_decl(t, id, add_to_current_scope))
+    rdr.map_xml_node_to_decl(node, t);
 
   type_base_sptr pointed_to_type =
-    ctxt.build_or_get_type_decl(type_id,/*add_to_current_scope=*/ true);
+    rdr.build_or_get_type_decl(type_id,/*add_to_current_scope=*/ true);
   ABG_ASSERT(pointed_to_type);
   t->set_pointed_to_type(pointed_to_type);
-  RECORD_ARTIFACT_AS_USED_BY(ctxt, pointed_to_type, t);
+  RECORD_ARTIFACT_AS_USED_BY(rdr, pointed_to_type, t);
 
   return t;
 }
@@ -4146,7 +3992,7 @@ build_reference_type_def(read_context&		ctxt,
 /// Build a function_type from a pointer to 'function-type'
 /// xml node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to build the function_type from.
 ///
@@ -4156,7 +4002,7 @@ build_reference_type_def(read_context&		ctxt,
 /// @return a pointer to a newly built function_type upon
 /// successful completion, a null pointer otherwise.
 static function_type_sptr
-build_function_type(read_context&	ctxt,
+build_function_type(reader&	rdr,
 		    const xmlNodePtr	node,
 		    bool /*add_to_current_scope*/)
 {
@@ -4176,34 +4022,32 @@ build_function_type(read_context&	ctxt,
 
   bool is_method_t = !method_class_id.empty();
 
-  size_t size = ctxt.get_translation_unit()->get_address_size(), align = 0;
+  size_t size = rdr.get_translation_unit()->get_address_size(), align = 0;
   read_size_and_alignment(node, size, align);
 
-  environment* env = ctxt.get_environment();
-  ABG_ASSERT(env);
+  const environment& env = rdr.get_environment();
   std::vector<shared_ptr<function_decl::parameter> > parms;
-  type_base_sptr return_type = env->get_void_type();
+  type_base_sptr return_type = env.get_void_type();
 
   class_or_union_sptr method_class_type;
   if (is_method_t)
     {
       method_class_type =
-	is_class_or_union_type(ctxt.build_or_get_type_decl(method_class_id,
+	is_class_or_union_type(rdr.build_or_get_type_decl(method_class_id,
 							   /*add_decl_to_scope=*/true));
       ABG_ASSERT(method_class_type);
     }
 
-
  function_type_sptr fn_type(is_method_t
 			    ? new method_type(method_class_type,
-					      ctxt.get_environment(),
+					      /*is_const=*/false,
 					      size, align)
 			    : new function_type(return_type,
 						parms, size, align));
 
-  ctxt.get_translation_unit()->bind_function_type_life_time(fn_type);
-  ctxt.key_type_decl(fn_type, id);
-  RECORD_ARTIFACTS_AS_USED_IN_FN_TYPE(ctxt, fn_type);
+  rdr.get_translation_unit()->bind_function_type_life_time(fn_type);
+  rdr.key_type_decl(fn_type, id);
+  RECORD_ARTIFACTS_AS_USED_IN_FN_TYPE(rdr, fn_type);
 
   for (xmlNodePtr n = xmlFirstElementChild(node);
        n;
@@ -4212,7 +4056,7 @@ build_function_type(read_context&	ctxt,
       if (xmlStrEqual(n->name, BAD_CAST("parameter")))
 	{
 	  if (function_decl::parameter_sptr p =
-	      build_function_parameter(ctxt, n))
+	      build_function_parameter(rdr, n))
 	    parms.push_back(p);
 	}
       else if (xmlStrEqual(n->name, BAD_CAST("return")))
@@ -4222,7 +4066,7 @@ build_function_type(read_context&	ctxt,
 	      xml::build_sptr(xmlGetProp(n, BAD_CAST("type-id"))))
 	    type_id = CHAR_STR(s);
 	  if (!type_id.empty())
-	    fn_type->set_return_type(ctxt.build_or_get_type_decl
+	    fn_type->set_return_type(rdr.build_or_get_type_decl
 				     (type_id, true));
 	}
     }
@@ -4234,7 +4078,7 @@ build_function_type(read_context&	ctxt,
 
 /// Build a array_type_def::subrange_type from a 'subrange' xml node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to build the
 /// array_type_def::subrange_type from.
@@ -4243,7 +4087,7 @@ build_function_type(read_context&	ctxt,
 /// @return a pointer to a newly built array_type_def::subrange_type
 /// upon successful completion, a null pointer otherwise.
 static array_type_def::subrange_sptr
-build_subrange_type(read_context&	ctxt,
+build_subrange_type(reader&	rdr,
 		    const xmlNodePtr	node)
 {
   array_type_def::subrange_sptr nil;
@@ -4251,7 +4095,7 @@ build_subrange_type(read_context&	ctxt,
   if (!node || !xmlStrEqual(node->name, BAD_CAST("subrange")))
     return nil;
 
-  if (decl_base_sptr d = ctxt.get_decl_for_xml_node(node))
+  if (decl_base_sptr d = rdr.get_decl_for_xml_node(node))
     {
       array_type_def::subrange_sptr result =
 	dynamic_pointer_cast<array_type_def::subrange_type>(d);
@@ -4268,7 +4112,7 @@ build_subrange_type(read_context&	ctxt,
     id = CHAR_STR(s);
 
   if (!id.empty())
-    if (type_base_sptr d = ctxt.get_type_decl(id))
+    if (type_base_sptr d = rdr.get_type_decl(id))
       {
 	array_type_def::subrange_sptr ty = is_subrange_type(d);
 	ABG_ASSERT(ty);
@@ -4310,12 +4154,12 @@ build_subrange_type(read_context&	ctxt,
   type_base_sptr underlying_type;
   if (!underlying_type_id.empty())
     {
-      underlying_type = ctxt.build_or_get_type_decl(underlying_type_id, true);
+      underlying_type = rdr.build_or_get_type_decl(underlying_type_id, true);
       ABG_ASSERT(underlying_type);
     }
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
 
   // Note that DWARF would actually have a lower_bound of -1 for an
   // array of length 0.
@@ -4337,10 +4181,10 @@ build_subrange_type(read_context&	ctxt,
     }
 
   array_type_def::subrange_sptr p
-    (new array_type_def::subrange_type(ctxt.get_environment(),
+    (new array_type_def::subrange_type(rdr.get_environment(),
 				       name, min_bound, max_bound,
 				       underlying_type, loc));
-  maybe_set_artificial_location(ctxt, node, p);
+  maybe_set_artificial_location(rdr, node, p);
   p->is_infinite(is_infinite);
 
   return p;
@@ -4348,7 +4192,7 @@ build_subrange_type(read_context&	ctxt,
 
 /// Build a array_type_def from a 'array-type-def' xml node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to build the array_type_def from.
 ///
@@ -4358,7 +4202,7 @@ build_subrange_type(read_context&	ctxt,
 /// @return a pointer to a newly built array_type_def upon
 /// successful completion, a null pointer otherwise.
 static array_type_def_sptr
-build_array_type_def(read_context&	ctxt,
+build_array_type_def(reader&	rdr,
 		     const		xmlNodePtr node,
 		     bool		add_to_current_scope)
 {
@@ -4368,7 +4212,7 @@ build_array_type_def(read_context&	ctxt,
   if (!xmlStrEqual(node->name, BAD_CAST("array-type-def")))
     return nil;
 
-  if (decl_base_sptr d = ctxt.get_decl_for_xml_node(node))
+  if (decl_base_sptr d = rdr.get_decl_for_xml_node(node))
     {
       array_type_def_sptr result =
 	dynamic_pointer_cast<array_type_def>(d);
@@ -4381,7 +4225,7 @@ build_array_type_def(read_context&	ctxt,
     id = CHAR_STR(s);
   ABG_ASSERT(!id.empty());
 
-  if (type_base_sptr d = ctxt.get_type_decl(id))
+  if (type_base_sptr d = rdr.get_type_decl(id))
     {
       array_type_def_sptr ty = is_array_type(d);
       ABG_ASSERT(ty);
@@ -4398,7 +4242,7 @@ build_array_type_def(read_context&	ctxt,
 
   // maybe building the type of array elements triggered building this
   // one in the mean time ...
-  if (decl_base_sptr d = ctxt.get_decl_for_xml_node(node))
+  if (decl_base_sptr d = rdr.get_decl_for_xml_node(node))
     {
       array_type_def_sptr result =
 	dynamic_pointer_cast<array_type_def>(d);
@@ -4431,7 +4275,7 @@ build_array_type_def(read_context&	ctxt,
     }
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
   array_type_def::subranges_type subranges;
 
   for (xmlNodePtr n = xmlFirstElementChild(node);
@@ -4440,13 +4284,13 @@ build_array_type_def(read_context&	ctxt,
     if (xmlStrEqual(n->name, BAD_CAST("subrange")))
       {
 	if (array_type_def::subrange_sptr s =
-	    build_subrange_type(ctxt, n))
+	    build_subrange_type(rdr, n))
 	  {
 	    MAYBE_MAP_TYPE_WITH_TYPE_ID(s, n);
 	    if (add_to_current_scope)
 	      {
-		add_decl_to_scope(s, ctxt.get_cur_scope());
-		ctxt.maybe_canonicalize_type(s);
+		add_decl_to_scope(s, rdr.get_cur_scope());
+		rdr.maybe_canonicalize_type(s);
 	      }
 	    subranges.push_back(s);
 	  }
@@ -4454,14 +4298,14 @@ build_array_type_def(read_context&	ctxt,
 
   // The type of array elements.
   type_base_sptr type =
-    ctxt.build_or_get_type_decl(type_id, true);
+    rdr.build_or_get_type_decl(type_id, true);
   ABG_ASSERT(type);
 
   array_type_def_sptr ar_type(new array_type_def(type, subranges, loc));
-  maybe_set_artificial_location(ctxt, node, ar_type);
-  if (ctxt.push_and_key_type_decl(ar_type, id, add_to_current_scope))
-    ctxt.map_xml_node_to_decl(node, ar_type);
-  RECORD_ARTIFACT_AS_USED_BY(ctxt, type, ar_type);
+  maybe_set_artificial_location(rdr, node, ar_type);
+  if (rdr.push_and_key_type_decl(ar_type, id, add_to_current_scope))
+    rdr.map_xml_node_to_decl(node, ar_type);
+  RECORD_ARTIFACT_AS_USED_BY(rdr, type, ar_type);
 
   if (dimensions != ar_type->get_dimension_count()
       || (alignment_in_bits
@@ -4508,9 +4352,9 @@ build_array_type_def(read_context&	ctxt,
 
 /// Build an @ref enum_type_decl from the XML node that represents it,
 /// if it was not suppressed by a supression specification present in
-/// the current read_context.
+/// the current reader.
 ///
-/// @param ctxt the read_context to take into account.
+/// @param rdr the reader to take into account.
 ///
 /// @param node the XML node representing the @ref enum_type_decl to
 /// build.
@@ -4521,19 +4365,19 @@ build_array_type_def(read_context&	ctxt,
 /// @return the newly built @ref enum_type_decl iff it was effectively
 /// built.
 static enum_type_decl_sptr
-build_enum_type_decl_if_not_suppressed(read_context&	ctxt,
+build_enum_type_decl_if_not_suppressed(reader&	rdr,
 				       const xmlNodePtr node,
 				       bool		add_to_current_scope)
 {
   enum_type_decl_sptr enum_type;
-  if (!type_is_suppressed(ctxt, node))
-    enum_type = build_enum_type_decl(ctxt, node, add_to_current_scope);
+  if (!type_is_suppressed(rdr, node))
+    enum_type = build_enum_type_decl(rdr, node, add_to_current_scope);
   return enum_type;
 }
 
 /// Build an enum_type_decl from an 'enum-type-decl' xml node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to build the enum_type_decl from.
 ///
@@ -4543,7 +4387,7 @@ build_enum_type_decl_if_not_suppressed(read_context&	ctxt,
 /// @return a pointer to a newly built enum_type_decl upon successful
 /// completion, a null pointer otherwise.
 static enum_type_decl_sptr
-build_enum_type_decl(read_context&	ctxt,
+build_enum_type_decl(reader&	rdr,
 		     const xmlNodePtr	node,
 		     bool		add_to_current_scope)
 {
@@ -4552,7 +4396,7 @@ build_enum_type_decl(read_context&	ctxt,
   if (!xmlStrEqual(node->name, BAD_CAST("enum-decl")))
     return nil;
 
-  if (decl_base_sptr d = ctxt.get_decl_for_xml_node(node))
+  if (decl_base_sptr d = rdr.get_decl_for_xml_node(node))
     {
       enum_type_decl_sptr result =
 	dynamic_pointer_cast<enum_type_decl>(d);
@@ -4569,7 +4413,7 @@ build_enum_type_decl(read_context&	ctxt,
     linkage_name = xml::unescape_xml_string(CHAR_STR(s));
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
 
   bool is_decl_only = false;
   read_is_declaration_only(node, is_decl_only);
@@ -4586,9 +4430,6 @@ build_enum_type_decl(read_context&	ctxt,
 
   ABG_ASSERT(!id.empty());
 
-  const environment* env = ctxt.get_environment();
-  ABG_ASSERT(env);
-
   string base_type_id;
   enum_type_decl::enumerators enums;
   for (xmlNodePtr n = xmlFirstElementChild(node);
@@ -4623,26 +4464,26 @@ build_enum_type_decl(read_context&	ctxt,
 		return nil;
 	    }
 
-	  enums.push_back(enum_type_decl::enumerator(env, name, value));
+	  enums.push_back(enum_type_decl::enumerator(name, value));
 	}
     }
 
   type_base_sptr underlying_type =
-    ctxt.build_or_get_type_decl(base_type_id, true);
+    rdr.build_or_get_type_decl(base_type_id, true);
   ABG_ASSERT(underlying_type);
 
   enum_type_decl_sptr t(new enum_type_decl(name, loc,
 					   underlying_type,
 					   enums, linkage_name));
-  maybe_set_artificial_location(ctxt, node, t);
+  maybe_set_artificial_location(rdr, node, t);
   t->set_is_anonymous(is_anonymous);
   t->set_is_artificial(is_artificial);
   t->set_is_declaration_only(is_decl_only);
-  if (ctxt.push_and_key_type_decl(t, id, add_to_current_scope))
+  if (rdr.push_and_key_type_decl(t, id, add_to_current_scope))
     {
-      maybe_set_naming_typedef(ctxt, node, t);
-      ctxt.map_xml_node_to_decl(node, t);
-      RECORD_ARTIFACT_AS_USED_BY(ctxt, underlying_type, t);
+      maybe_set_naming_typedef(rdr, node, t);
+      rdr.map_xml_node_to_decl(node, t);
+      RECORD_ARTIFACT_AS_USED_BY(rdr, underlying_type, t);
       return t;
     }
 
@@ -4651,14 +4492,14 @@ build_enum_type_decl(read_context&	ctxt,
 
 /// Build a typedef_decl from a 'typedef-decl' xml node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to build the typedef_decl from.
 ///
 /// @return a pointer to a newly built typedef_decl upon successful
 /// completion, a null pointer otherwise.
 static shared_ptr<typedef_decl>
-build_typedef_decl(read_context&	ctxt,
+build_typedef_decl(reader&	rdr,
 		   const xmlNodePtr	node,
 		   bool		add_to_current_scope)
 {
@@ -4667,7 +4508,7 @@ build_typedef_decl(read_context&	ctxt,
   if (!xmlStrEqual(node->name, BAD_CAST("typedef-decl")))
     return nil;
 
-  if (decl_base_sptr d = ctxt.get_decl_for_xml_node(node))
+  if (decl_base_sptr d = rdr.get_decl_for_xml_node(node))
     {
       typedef_decl_sptr result = is_typedef(d);
       ABG_ASSERT(result);
@@ -4679,7 +4520,7 @@ build_typedef_decl(read_context&	ctxt,
     id = CHAR_STR(s);
   ABG_ASSERT(!id.empty());
 
-  if (type_base_sptr t = ctxt.get_type_decl(id))
+  if (type_base_sptr t = rdr.get_type_decl(id))
     {
       typedef_decl_sptr result = is_typedef(t);
       ABG_ASSERT(result);
@@ -4691,29 +4532,29 @@ build_typedef_decl(read_context&	ctxt,
     name = xml::unescape_xml_string(CHAR_STR(s));
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
 
   string type_id;
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "type-id"))
     type_id = CHAR_STR(s);
   ABG_ASSERT(!type_id.empty());
 
-  type_base_sptr underlying_type(ctxt.build_or_get_type_decl(type_id, true));
+  type_base_sptr underlying_type(rdr.build_or_get_type_decl(type_id, true));
   ABG_ASSERT(underlying_type);
 
   typedef_decl_sptr t(new typedef_decl(name, underlying_type, loc));
-  maybe_set_artificial_location(ctxt, node, t);
-  ctxt.push_and_key_type_decl(t, id, add_to_current_scope);
-  ctxt.map_xml_node_to_decl(node, t);
-  RECORD_ARTIFACT_AS_USED_BY(ctxt, underlying_type, t);
+  maybe_set_artificial_location(rdr, node, t);
+  rdr.push_and_key_type_decl(t, id, add_to_current_scope);
+  rdr.map_xml_node_to_decl(node, t);
+  RECORD_ARTIFACT_AS_USED_BY(rdr, underlying_type, t);
 
   return t;
 }
 
 /// Build a class from its XML node if it is not suppressed by a
-/// suppression specification that is present in the read context.
+/// suppression specification that is present in the ABIXML reader.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the ABIXML reader to consider.
 ///
 /// @param node the XML node to consider.
 ///
@@ -4722,13 +4563,13 @@ build_typedef_decl(read_context&	ctxt,
 ///
 /// @return true iff the class was built.
 static class_decl_sptr
-build_class_decl_if_not_suppressed(read_context&	ctxt,
+build_class_decl_if_not_suppressed(reader&	rdr,
 				   const xmlNodePtr	node,
 				   bool		add_to_current_scope)
 {
   class_decl_sptr class_type;
-  if (!type_is_suppressed(ctxt, node))
-    class_type = build_class_decl(ctxt, node, add_to_current_scope);
+  if (!type_is_suppressed(rdr, node))
+    class_type = build_class_decl(rdr, node, add_to_current_scope);
   return class_type;
 }
 
@@ -4736,7 +4577,7 @@ build_class_decl_if_not_suppressed(read_context&	ctxt,
 /// by a suppression specification that is present in the read
 /// context.
 ///
-/// @param ctxt the read context to consider.
+/// @param rdr the ABIXML reader to consider.
 ///
 /// @param node the XML node to consider.
 ///
@@ -4745,19 +4586,19 @@ build_class_decl_if_not_suppressed(read_context&	ctxt,
 ///
 /// @return true iff the @ref union_decl was built.
 static union_decl_sptr
-build_union_decl_if_not_suppressed(read_context&	ctxt,
+build_union_decl_if_not_suppressed(reader&	rdr,
 				   const xmlNodePtr	node,
 				   bool		add_to_current_scope)
 {
   union_decl_sptr union_type;
-  if (!type_is_suppressed(ctxt, node))
-    union_type = build_union_decl(ctxt, node, add_to_current_scope);
+  if (!type_is_suppressed(rdr, node))
+    union_type = build_union_decl(rdr, node, add_to_current_scope);
   return union_type;
 }
 
 /// Build a class_decl from a 'class-decl' xml node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to build the class_decl from.
 ///
@@ -4768,7 +4609,7 @@ build_union_decl_if_not_suppressed(read_context&	ctxt,
 /// @return a pointer to class_decl upon successful completion, a null
 /// pointer otherwise.
 static class_decl_sptr
-build_class_decl(read_context&		ctxt,
+build_class_decl(reader&		rdr,
 		 const xmlNodePtr	node,
 		 bool			add_to_current_scope)
 {
@@ -4777,7 +4618,7 @@ build_class_decl(read_context&		ctxt,
   if (!xmlStrEqual(node->name, BAD_CAST("class-decl")))
     return nil;
 
-  if (decl_base_sptr d = ctxt.get_decl_for_xml_node(node))
+  if (decl_base_sptr d = rdr.get_decl_for_xml_node(node))
     {
       class_decl_sptr result = dynamic_pointer_cast<class_decl>(d);
       ABG_ASSERT(result);
@@ -4802,7 +4643,7 @@ build_class_decl(read_context&		ctxt,
     id = CHAR_STR(s);
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
 
   class_decl::member_types mbrs;
   class_decl::data_members data_mbrs;
@@ -4824,7 +4665,7 @@ build_class_decl(read_context&		ctxt,
 
   class_decl_sptr previous_definition, previous_declaration;
   if (!is_anonymous)
-    if (type_base_sptr t = ctxt.get_type_decl(id))
+    if (type_base_sptr t = rdr.get_type_decl(id))
       {
 	previous_definition  = is_class_type(t);
 	ABG_ASSERT(previous_definition);
@@ -4832,7 +4673,7 @@ build_class_decl(read_context&		ctxt,
 
   const vector<type_base_sptr> *types_ptr = 0;
   if (!is_anonymous && !previous_definition)
-    types_ptr = ctxt.get_all_type_decls(id);
+    types_ptr = rdr.get_all_type_decls(id);
   if (types_ptr)
     {
       // Lets look at the previous declarations and the first previous
@@ -4864,8 +4705,7 @@ build_class_decl(read_context&		ctxt,
 	return previous_declaration;
     }
 
-  const environment* env = ctxt.get_environment();
-  ABG_ASSERT(env);
+  const environment& env = rdr.get_environment();
 
   if (!is_decl_only && previous_definition)
     // We are in the case where we've read this class definition
@@ -4891,7 +4731,7 @@ build_class_decl(read_context&		ctxt,
 				  data_mbrs, mbr_functions, is_anonymous));
     }
 
-  maybe_set_artificial_location(ctxt, node, decl);
+  maybe_set_artificial_location(rdr, node, decl);
   decl->set_is_artificial(is_artificial);
 
   string def_id;
@@ -4901,7 +4741,7 @@ build_class_decl(read_context&		ctxt,
 
   if (!def_id.empty())
     {
-      decl_base_sptr d = is_decl(ctxt.get_type_decl(def_id));
+      decl_base_sptr d = is_decl(rdr.get_type_decl(def_id));
       if (d && d->get_is_declaration_only())
 	{
 	  is_def_of_decl = true;
@@ -4946,13 +4786,13 @@ build_class_decl(read_context&		ctxt,
 
   ABG_ASSERT(!is_decl_only || !is_def_of_decl);
 
-  ctxt.push_decl_to_current_scope(decl, add_to_current_scope);
+  rdr.push_decl_to_current_scope(decl, add_to_current_scope);
 
-  ctxt.map_xml_node_to_decl(node, decl);
-  ctxt.key_type_decl(decl, id);
+  rdr.map_xml_node_to_decl(node, decl);
+  rdr.key_type_decl(decl, id);
 
   // If this class has a naming typedef, get it and refer to it.
-  maybe_set_naming_typedef(ctxt, node, decl);
+  maybe_set_naming_typedef(rdr, node, decl);
 
   for (xmlNodePtr n = xmlFirstElementChild(node);
        !is_decl_only && n;
@@ -4971,7 +4811,7 @@ build_class_decl(read_context&		ctxt,
 	    type_id = CHAR_STR(s);
 	  shared_ptr<class_decl> b =
 	    dynamic_pointer_cast<class_decl>
-	    (ctxt.build_or_get_type_decl(type_id, true));
+	    (rdr.build_or_get_type_decl(type_id, true));
 	  ABG_ASSERT(b);
 
 	  if (decl->find_base_class(b->get_qualified_name()))
@@ -5002,30 +4842,30 @@ build_class_decl(read_context&		ctxt,
 	    : private_access;
 	  read_access(n, access);
 
-	  ctxt.map_xml_node_to_decl(n, decl);
+	  rdr.map_xml_node_to_decl(n, decl);
 
 	  for (xmlNodePtr p = xmlFirstElementChild(n);
 	       p;
 	       p = xmlNextElementSibling(p))
 	    {
 	      if (type_base_sptr t =
-		  build_type(ctxt, p, /*add_to_current_scope=*/true))
+		  build_type(rdr, p, /*add_to_current_scope=*/true))
 		{
 		  decl_base_sptr td = get_type_declaration(t);
 		  ABG_ASSERT(td);
 		  set_member_access_specifier(td, access);
-		  ctxt.maybe_canonicalize_type(t, !add_to_current_scope);
+		  rdr.maybe_canonicalize_type(t, !add_to_current_scope);
 		  xml_char_sptr i= XML_NODE_GET_ATTRIBUTE(p, "id");
 		  string id = CHAR_STR(i);
 		  ABG_ASSERT(!id.empty());
-		  ctxt.key_type_decl(t, id);
-		  ctxt.map_xml_node_to_decl(p, td);
+		  rdr.key_type_decl(t, id);
+		  rdr.map_xml_node_to_decl(p, td);
 		}
 	    }
 	}
       else if (xmlStrEqual(n->name, BAD_CAST("data-member")))
 	{
-	  ctxt.map_xml_node_to_decl(n, decl);
+	  rdr.map_xml_node_to_decl(n, decl);
 
 	  access_specifier access =
 	    is_struct
@@ -5046,7 +4886,7 @@ build_class_decl(read_context&		ctxt,
 	       p = xmlNextElementSibling(p))
 	    {
 	      if (var_decl_sptr v =
-		  build_var_decl(ctxt, p, /*add_to_cur_scope=*/false))
+		  build_var_decl(rdr, p, /*add_to_cur_scope=*/false))
 		{
 		  if (decl->find_data_member(v))
 		    {
@@ -5056,19 +4896,19 @@ build_class_decl(read_context&		ctxt,
 		      // So we need to discard the data member we have
 		      // built (and that was pushed to the current
 		      // stack of decls built) and move on.
-		      decl_base_sptr d = ctxt.pop_decl();
+		      decl_base_sptr d = rdr.pop_decl();
 		      ABG_ASSERT(is_var_decl(d));
 		      continue;
 		    }
 
-		  if (!variable_is_suppressed(ctxt, decl.get(), *v))
+		  if (!variable_is_suppressed(rdr, decl.get(), *v))
 		    {
 		      decl->add_data_member(v, access,
 					    is_laid_out,
 					    is_static,
 					    offset_in_bits);
 		      if (is_static)
-			ctxt.maybe_add_var_to_exported_decls(v.get());
+			rdr.maybe_add_var_to_exported_decls(v.get());
 		      // Now let's record the fact that the data
 		      // member uses its type and that the class being
 		      // built uses the data member.
@@ -5078,11 +4918,11 @@ build_class_decl(read_context&		ctxt,
 			// can't name it.  Rather, let's record that
 			// the class being built uses the type of the
 			// (anonymous) data member.
-			RECORD_ARTIFACT_AS_USED_BY(ctxt, v->get_type(), decl);
+			RECORD_ARTIFACT_AS_USED_BY(rdr, v->get_type(), decl);
 		      else
 			{
-			  RECORD_ARTIFACT_AS_USED_BY(ctxt, v->get_type(), v);
-			  RECORD_ARTIFACT_AS_USED_BY(ctxt, v, decl);
+			  RECORD_ARTIFACT_AS_USED_BY(rdr, v->get_type(), v);
+			  RECORD_ARTIFACT_AS_USED_BY(rdr, v, decl);
 			}
 		    }
 		}
@@ -5090,7 +4930,7 @@ build_class_decl(read_context&		ctxt,
 	}
       else if (xmlStrEqual(n->name, BAD_CAST("member-function")))
 	{
-	  ctxt.map_xml_node_to_decl(n, decl);
+	  rdr.map_xml_node_to_decl(n, decl);
 
 	  access_specifier access =
 	    is_struct
@@ -5118,7 +4958,7 @@ build_class_decl(read_context&		ctxt,
 	       p = xmlNextElementSibling(p))
 	    {
 	      if (function_decl_sptr f =
-		  build_function_decl_if_not_suppressed(ctxt, p, decl,
+		  build_function_decl_if_not_suppressed(rdr, p, decl,
 							/*add_to_cur_sc=*/true))
 		{
 		  method_decl_sptr m = is_method_decl(f);
@@ -5137,7 +4977,7 @@ build_class_decl(read_context&		ctxt,
 	}
       else if (xmlStrEqual(n->name, BAD_CAST("member-template")))
 	{
-	  ctxt.map_xml_node_to_decl(n, decl);
+	  rdr.map_xml_node_to_decl(n, decl);
 
 	  access_specifier access =
 	    is_struct
@@ -5156,7 +4996,7 @@ build_class_decl(read_context&		ctxt,
 	       p = xmlNextElementSibling(p))
 	    {
 	      if (shared_ptr<function_tdecl> f =
-		  build_function_tdecl(ctxt, p,
+		  build_function_tdecl(rdr, p,
 				       /*add_to_current_scope=*/true))
 		{
 		  shared_ptr<member_function_template> m
@@ -5166,7 +5006,7 @@ build_class_decl(read_context&		ctxt,
 		  decl->add_member_function_template(m);
 		}
 	      else if (shared_ptr<class_tdecl> c =
-		       build_class_tdecl(ctxt, p,
+		       build_class_tdecl(rdr, p,
 					 /*add_to_current_scope=*/true))
 		{
 		  member_class_template_sptr m(new member_class_template(c,
@@ -5179,14 +5019,14 @@ build_class_decl(read_context&		ctxt,
 	}
     }
 
-  ctxt.pop_scope_or_abort(decl);
+  rdr.pop_scope_or_abort(decl);
 
   return decl;
 }
 
 /// Build a union_decl from a 'union-decl' xml node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to build the union_decl from.
 ///
@@ -5197,7 +5037,7 @@ build_class_decl(read_context&		ctxt,
 /// @return a pointer to union_decl upon successful completion, a null
 /// pointer otherwise.
 static union_decl_sptr
-build_union_decl(read_context& ctxt,
+build_union_decl(reader& rdr,
 		 const xmlNodePtr node,
 		 bool add_to_current_scope)
 {
@@ -5206,7 +5046,7 @@ build_union_decl(read_context& ctxt,
   if (!xmlStrEqual(node->name, BAD_CAST("union-decl")))
     return nil;
 
-  if (decl_base_sptr d = ctxt.get_decl_for_xml_node(node))
+  if (decl_base_sptr d = rdr.get_decl_for_xml_node(node))
     {
       union_decl_sptr result = dynamic_pointer_cast<union_decl>(d);
       ABG_ASSERT(result);
@@ -5231,7 +5071,7 @@ build_union_decl(read_context& ctxt,
     id = CHAR_STR(s);
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
 
   union_decl::member_types mbrs;
   union_decl::data_members data_mbrs;
@@ -5249,7 +5089,7 @@ build_union_decl(read_context& ctxt,
   union_decl_sptr previous_definition, previous_declaration;
   const vector<type_base_sptr> *types_ptr = 0;
   if (!is_anonymous)
-    types_ptr = ctxt.get_all_type_decls(id);
+    types_ptr = rdr.get_all_type_decls(id);
   if (types_ptr)
     {
       // Lets look at the previous declarations and the first previous
@@ -5281,8 +5121,7 @@ build_union_decl(read_context& ctxt,
 	return previous_declaration;
     }
 
-  const environment* env = ctxt.get_environment();
-  ABG_ASSERT(env);
+  const environment& env = rdr.get_environment();
 
   if (!is_decl_only && previous_definition)
     // We are in the case where we've read this class definition
@@ -5304,7 +5143,7 @@ build_union_decl(read_context& ctxt,
 				  is_anonymous));
     }
 
-  maybe_set_artificial_location(ctxt, node, decl);
+  maybe_set_artificial_location(rdr, node, decl);
   decl->set_is_artificial(is_artificial);
 
   string def_id;
@@ -5315,7 +5154,7 @@ build_union_decl(read_context& ctxt,
   if (!def_id.empty())
     {
       class_decl_sptr d =
-	dynamic_pointer_cast<class_decl>(ctxt.get_type_decl(def_id));
+	dynamic_pointer_cast<class_decl>(rdr.get_type_decl(def_id));
       if (d && d->get_is_declaration_only())
 	{
 	  is_def_of_decl = true;
@@ -5360,12 +5199,12 @@ build_union_decl(read_context& ctxt,
 
   ABG_ASSERT(!is_decl_only || !is_def_of_decl);
 
-  ctxt.push_decl_to_current_scope(decl, add_to_current_scope);
+  rdr.push_decl_to_current_scope(decl, add_to_current_scope);
 
-  ctxt.map_xml_node_to_decl(node, decl);
-  ctxt.key_type_decl(decl, id);
+  rdr.map_xml_node_to_decl(node, decl);
+  rdr.key_type_decl(decl, id);
 
-  maybe_set_naming_typedef(ctxt, node, decl);
+  maybe_set_naming_typedef(rdr, node, decl);
 
   for (xmlNodePtr n = xmlFirstElementChild(node);
        !is_decl_only && n;
@@ -5376,30 +5215,30 @@ build_union_decl(read_context& ctxt,
 	  access_specifier access = private_access;
 	  read_access(n, access);
 
-	  ctxt.map_xml_node_to_decl(n, decl);
+	  rdr.map_xml_node_to_decl(n, decl);
 
 	  for (xmlNodePtr p = xmlFirstElementChild(n);
 	       p;
 	       p = xmlNextElementSibling(p))
 	    {
 	      if (type_base_sptr t =
-		  build_type(ctxt, p, /*add_to_current_scope=*/true))
+		  build_type(rdr, p, /*add_to_current_scope=*/true))
 		{
 		  decl_base_sptr td = get_type_declaration(t);
 		  ABG_ASSERT(td);
 		  set_member_access_specifier(td, access);
-		  ctxt.maybe_canonicalize_type(t, !add_to_current_scope);
+		  rdr.maybe_canonicalize_type(t, !add_to_current_scope);
 		  xml_char_sptr i= XML_NODE_GET_ATTRIBUTE(p, "id");
 		  string id = CHAR_STR(i);
 		  ABG_ASSERT(!id.empty());
-		  ctxt.key_type_decl(t, id);
-		  ctxt.map_xml_node_to_decl(p, td);
+		  rdr.key_type_decl(t, id);
+		  rdr.map_xml_node_to_decl(p, td);
 		}
 	    }
 	}
       else if (xmlStrEqual(n->name, BAD_CAST("data-member")))
 	{
-	  ctxt.map_xml_node_to_decl(n, decl);
+	  rdr.map_xml_node_to_decl(n, decl);
 
 	  access_specifier access = private_access;
 	  read_access(n, access);
@@ -5414,7 +5253,7 @@ build_union_decl(read_context& ctxt,
 	       p = xmlNextElementSibling(p))
 	    {
 	      if (var_decl_sptr v =
-		  build_var_decl(ctxt, p, /*add_to_cur_scope=*/false))
+		  build_var_decl(rdr, p, /*add_to_cur_scope=*/false))
 		{
 		  if (decl->find_data_member(v))
 		    {
@@ -5424,12 +5263,12 @@ build_union_decl(read_context& ctxt,
 		      // So we need to discard the data member we have
 		      // built (and that was pushed to the current
 		      // stack of decls built) and move on.
-		      decl_base_sptr d = ctxt.pop_decl();
+		      decl_base_sptr d = rdr.pop_decl();
 		      ABG_ASSERT(is_var_decl(d));
 		      continue;
 		    }
 		  if (!is_static
-		      || !variable_is_suppressed(ctxt, decl.get(), *v))
+		      || !variable_is_suppressed(rdr, decl.get(), *v))
 		    {
 		      decl->add_data_member(v, access,
 					    is_laid_out,
@@ -5444,11 +5283,11 @@ build_union_decl(read_context& ctxt,
 			// can't name it.  Rather, let's record that
 			// the class being built uses the type of the
 			// (anonymous) data member.
-			RECORD_ARTIFACT_AS_USED_BY(ctxt, v->get_type(), decl);
+			RECORD_ARTIFACT_AS_USED_BY(rdr, v->get_type(), decl);
 		      else
 			{
-			  RECORD_ARTIFACT_AS_USED_BY(ctxt, v->get_type(), v);
-			  RECORD_ARTIFACT_AS_USED_BY(ctxt, v, decl);
+			  RECORD_ARTIFACT_AS_USED_BY(rdr, v->get_type(), v);
+			  RECORD_ARTIFACT_AS_USED_BY(rdr, v, decl);
 			}
 		    }
 		}
@@ -5456,7 +5295,7 @@ build_union_decl(read_context& ctxt,
 	}
       else if (xmlStrEqual(n->name, BAD_CAST("member-function")))
 	{
-	  ctxt.map_xml_node_to_decl(n, decl);
+	  rdr.map_xml_node_to_decl(n, decl);
 
 	  access_specifier access = private_access;
 	  read_access(n, access);
@@ -5472,7 +5311,7 @@ build_union_decl(read_context& ctxt,
 	       p = xmlNextElementSibling(p))
 	    {
 	      if (function_decl_sptr f =
-		  build_function_decl_if_not_suppressed(ctxt, p, decl,
+		  build_function_decl_if_not_suppressed(rdr, p, decl,
 							/*add_to_cur_sc=*/true))
 		{
 		  method_decl_sptr m = is_method_decl(f);
@@ -5488,7 +5327,7 @@ build_union_decl(read_context& ctxt,
 	}
       else if (xmlStrEqual(n->name, BAD_CAST("member-template")))
 	{
-	  ctxt.map_xml_node_to_decl(n, decl);
+	  rdr.map_xml_node_to_decl(n, decl);
 
 	  access_specifier access = private_access;
 	  read_access(n, access);
@@ -5504,7 +5343,7 @@ build_union_decl(read_context& ctxt,
 	       p = xmlNextElementSibling(p))
 	    {
 	      if (function_tdecl_sptr f =
-		  build_function_tdecl(ctxt, p,
+		  build_function_tdecl(rdr, p,
 				       /*add_to_current_scope=*/true))
 		{
 		  member_function_template_sptr m
@@ -5514,7 +5353,7 @@ build_union_decl(read_context& ctxt,
 		  decl->add_member_function_template(m);
 		}
 	      else if (class_tdecl_sptr c =
-		       build_class_tdecl(ctxt, p,
+		       build_class_tdecl(rdr, p,
 					 /*add_to_current_scope=*/true))
 		{
 		  member_class_template_sptr m(new member_class_template(c,
@@ -5527,7 +5366,7 @@ build_union_decl(read_context& ctxt,
 	}
     }
 
-  ctxt.pop_scope_or_abort(decl);
+  rdr.pop_scope_or_abort(decl);
 
   return decl;
 }
@@ -5535,7 +5374,7 @@ build_union_decl(read_context& ctxt,
 /// Build an intance of function_tdecl, from an
 /// 'function-template-decl' xml element node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to parse from.
 ///
@@ -5545,7 +5384,7 @@ build_union_decl(read_context& ctxt,
 /// @return the newly built function_tdecl upon successful
 /// completion, a null pointer otherwise.
 static shared_ptr<function_tdecl>
-build_function_tdecl(read_context& ctxt,
+build_function_tdecl(reader& rdr,
 		     const xmlNodePtr node,
 		     bool add_to_current_scope)
 {
@@ -5557,11 +5396,11 @@ build_function_tdecl(read_context& ctxt,
   string id;
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "id"))
     id = CHAR_STR(s);
-  if (id.empty() || ctxt.get_fn_tmpl_decl(id))
+  if (id.empty() || rdr.get_fn_tmpl_decl(id))
     return nil;
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
 
   decl_base::visibility vis = decl_base::VISIBILITY_NONE;
   read_visibility(node, vis);
@@ -5569,13 +5408,12 @@ build_function_tdecl(read_context& ctxt,
   decl_base::binding bind = decl_base::BINDING_NONE;
   read_binding(node, bind);
 
-  const environment* env = ctxt.get_environment();
-  ABG_ASSERT(env);
+  const environment& env = rdr.get_environment();
 
   function_tdecl_sptr fn_tmpl_decl(new function_tdecl(env, loc, vis, bind));
-  maybe_set_artificial_location(ctxt, node, fn_tmpl_decl);
+  maybe_set_artificial_location(rdr, node, fn_tmpl_decl);
 
-  ctxt.push_decl_to_current_scope(fn_tmpl_decl, add_to_current_scope);
+  rdr.push_decl_to_current_scope(fn_tmpl_decl, add_to_current_scope);
 
   unsigned parm_index = 0;
   for (xmlNodePtr n = xmlFirstElementChild(node);
@@ -5583,18 +5421,18 @@ build_function_tdecl(read_context& ctxt,
        n = xmlNextElementSibling(n))
     {
       if (template_parameter_sptr parm =
-	  build_template_parameter(ctxt, n, parm_index, fn_tmpl_decl))
+	  build_template_parameter(rdr, n, parm_index, fn_tmpl_decl))
 	{
 	  fn_tmpl_decl->add_template_parameter(parm);
 	  ++parm_index;
 	}
       else if (function_decl_sptr f =
-	       build_function_decl_if_not_suppressed(ctxt, n, class_decl_sptr(),
+	       build_function_decl_if_not_suppressed(rdr, n, class_decl_sptr(),
 					 /*add_to_current_scope=*/true))
 	fn_tmpl_decl->set_pattern(f);
     }
 
-  ctxt.key_fn_tmpl_decl(fn_tmpl_decl, id);
+  rdr.key_fn_tmpl_decl(fn_tmpl_decl, id);
 
   return fn_tmpl_decl;
 }
@@ -5602,7 +5440,7 @@ build_function_tdecl(read_context& ctxt,
 /// Build an intance of class_tdecl, from a
 /// 'class-template-decl' xml element node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to parse from.
 ///
@@ -5612,7 +5450,7 @@ build_function_tdecl(read_context& ctxt,
 /// @return the newly built function_tdecl upon successful
 /// completion, a null pointer otherwise.
 static shared_ptr<class_tdecl>
-build_class_tdecl(read_context&	ctxt,
+build_class_tdecl(reader&	rdr,
 		  const xmlNodePtr	node,
 		  bool			add_to_current_scope)
 {
@@ -5624,22 +5462,21 @@ build_class_tdecl(read_context&	ctxt,
   string id;
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "id"))
     id = CHAR_STR(s);
-  if (id.empty() || ctxt.get_class_tmpl_decl(id))
+  if (id.empty() || rdr.get_class_tmpl_decl(id))
     return nil;
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
 
   decl_base::visibility vis = decl_base::VISIBILITY_NONE;
   read_visibility(node, vis);
 
-  const environment* env = ctxt.get_environment();
-  ABG_ASSERT(env);
+  const environment& env = rdr.get_environment();
 
   class_tdecl_sptr class_tmpl (new class_tdecl(env, loc, vis));
-  maybe_set_artificial_location(ctxt, node, class_tmpl);
+  maybe_set_artificial_location(rdr, node, class_tmpl);
 
-  ctxt.push_decl_to_current_scope(class_tmpl, add_to_current_scope);
+  rdr.push_decl_to_current_scope(class_tmpl, add_to_current_scope);
 
   unsigned parm_index = 0;
   for (xmlNodePtr n = xmlFirstElementChild(node);
@@ -5647,22 +5484,22 @@ build_class_tdecl(read_context&	ctxt,
        n = xmlNextElementSibling(n))
     {
       if (template_parameter_sptr parm=
-	  build_template_parameter(ctxt, n, parm_index, class_tmpl))
+	  build_template_parameter(rdr, n, parm_index, class_tmpl))
 	{
 	  class_tmpl->add_template_parameter(parm);
 	  ++parm_index;
 	}
       else if (class_decl_sptr c =
-	       build_class_decl_if_not_suppressed(ctxt, n,
+	       build_class_decl_if_not_suppressed(rdr, n,
 						  add_to_current_scope))
 	{
 	  if (c->get_scope())
-	    ctxt.maybe_canonicalize_type(c, /*force_delay=*/false);
+	    rdr.maybe_canonicalize_type(c, /*force_delay=*/false);
 	  class_tmpl->set_pattern(c);
 	}
     }
 
-  ctxt.key_class_tmpl_decl(class_tmpl, id);
+  rdr.key_class_tmpl_decl(class_tmpl, id);
 
   return class_tmpl;
 }
@@ -5670,7 +5507,7 @@ build_class_tdecl(read_context&	ctxt,
 /// Build a type_tparameter from a 'template-type-parameter'
 /// xml element node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to parse from.
 ///
@@ -5683,7 +5520,7 @@ build_class_tdecl(read_context&	ctxt,
 /// @return a pointer to a newly created instance of
 /// type_tparameter, a null pointer otherwise.
 static type_tparameter_sptr
-build_type_tparameter(read_context&		ctxt,
+build_type_tparameter(reader&		rdr,
 		      const xmlNodePtr		node,
 		      unsigned			index,
 		      template_decl_sptr	tdecl)
@@ -5697,14 +5534,14 @@ build_type_tparameter(read_context&		ctxt,
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "id"))
     id = CHAR_STR(s);
   if (!id.empty())
-    ABG_ASSERT(!ctxt.get_type_decl(id));
+    ABG_ASSERT(!rdr.get_type_decl(id));
 
   string type_id;
   if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "type-id"))
     type_id = CHAR_STR(s);
   if (!type_id.empty()
       && !(result = dynamic_pointer_cast<type_tparameter>
-	   (ctxt.build_or_get_type_decl(type_id, true))))
+	   (rdr.build_or_get_type_decl(type_id, true))))
     abort();
 
   string name;
@@ -5712,20 +5549,18 @@ build_type_tparameter(read_context&		ctxt,
     name = xml::unescape_xml_string(CHAR_STR(s));
 
   location loc;
-  read_location(ctxt, node,loc);
+  read_location(rdr, node,loc);
 
   result.reset(new type_tparameter(index, tdecl, name, loc));
-  maybe_set_artificial_location(ctxt, node, result);
+  maybe_set_artificial_location(rdr, node, result);
 
   if (id.empty())
-    ctxt.push_decl_to_current_scope(dynamic_pointer_cast<decl_base>(result),
+    rdr.push_decl_to_current_scope(dynamic_pointer_cast<decl_base>(result),
 				    /*add_to_current_scope=*/true);
   else
-    ctxt.push_and_key_type_decl(result, id, /*add_to_current_scope=*/true);
+    rdr.push_and_key_type_decl(result, id, /*add_to_current_scope=*/true);
 
-  ABG_ASSERT(result->get_environment());
-
-  ctxt.maybe_canonicalize_type(result, /*force_delay=*/false);
+  rdr.maybe_canonicalize_type(result, /*force_delay=*/false);
 
   return result;
 }
@@ -5733,7 +5568,7 @@ build_type_tparameter(read_context&		ctxt,
 /// Build a tmpl_parm_type_composition from a
 /// "template-parameter-type-composition" xml element node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to parse from.
 ///
@@ -5745,7 +5580,7 @@ build_type_tparameter(read_context&		ctxt,
 /// @return a pointer to a new instance of tmpl_parm_type_composition
 /// upon successful completion, a null pointer otherwise.
 static type_composition_sptr
-build_type_composition(read_context&		ctxt,
+build_type_composition(reader&		rdr,
 		       const xmlNodePtr	node,
 		       unsigned		index,
 		       template_decl_sptr	tdecl)
@@ -5757,7 +5592,7 @@ build_type_composition(read_context&		ctxt,
 
   type_base_sptr composed_type;
   result.reset(new type_composition(index, tdecl, composed_type));
-  ctxt.push_decl_to_current_scope(dynamic_pointer_cast<decl_base>(result),
+  rdr.push_decl_to_current_scope(dynamic_pointer_cast<decl_base>(result),
 				  /*add_to_current_scope=*/true);
 
   for (xmlNodePtr n = xmlFirstElementChild(node);
@@ -5765,19 +5600,19 @@ build_type_composition(read_context&		ctxt,
        n = xmlNextElementSibling(n))
     {
       if ((composed_type =
-	   build_pointer_type_def(ctxt, n,
+	   build_pointer_type_def(rdr, n,
 				  /*add_to_current_scope=*/true))
 	  ||(composed_type =
-	     build_reference_type_def(ctxt, n,
+	     build_reference_type_def(rdr, n,
 				      /*add_to_current_scope=*/true))
 	  ||(composed_type =
-	     build_array_type_def(ctxt, n,
+	     build_array_type_def(rdr, n,
 				  /*add_to_current_scope=*/true))
 	  || (composed_type =
-	      build_qualified_type_decl(ctxt, n,
+	      build_qualified_type_decl(rdr, n,
 					/*add_to_current_scope=*/true)))
 	{
-	  ctxt.maybe_canonicalize_type(composed_type,
+	  rdr.maybe_canonicalize_type(composed_type,
 				       /*force_delay=*/true);
 	  result->set_composed_type(composed_type);
 	  break;
@@ -5790,7 +5625,7 @@ build_type_composition(read_context&		ctxt,
 /// Build an instance of non_type_tparameter from a
 /// 'template-non-type-parameter' xml element node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to parse from.
 ///
@@ -5803,7 +5638,7 @@ build_type_composition(read_context&		ctxt,
 /// non_type_tparameter upon successful completion, a null
 /// pointer code otherwise.
 static non_type_tparameter_sptr
-build_non_type_tparameter(read_context&	ctxt,
+build_non_type_tparameter(reader&	rdr,
 			  const xmlNodePtr	node,
 			  unsigned		index,
 			  template_decl_sptr	tdecl)
@@ -5818,7 +5653,7 @@ build_non_type_tparameter(read_context&	ctxt,
     type_id = CHAR_STR(s);
   type_base_sptr type;
   if (type_id.empty()
-      || !(type = ctxt.build_or_get_type_decl(type_id, true)))
+      || !(type = rdr.build_or_get_type_decl(type_id, true)))
     abort();
 
   string name;
@@ -5826,11 +5661,11 @@ build_non_type_tparameter(read_context&	ctxt,
     name = xml::unescape_xml_string(CHAR_STR(s));
 
   location loc;
-  read_location(ctxt, node,loc);
+  read_location(rdr, node,loc);
 
   r.reset(new non_type_tparameter(index, tdecl, name, type, loc));
-  maybe_set_artificial_location(ctxt, node, r);
-  ctxt.push_decl_to_current_scope(dynamic_pointer_cast<decl_base>(r),
+  maybe_set_artificial_location(rdr, node, r);
+  rdr.push_decl_to_current_scope(dynamic_pointer_cast<decl_base>(r),
 				  /*add_to_current_scope=*/true);
 
   return r;
@@ -5839,7 +5674,7 @@ build_non_type_tparameter(read_context&	ctxt,
 /// Build an intance of template_tparameter from a
 /// 'template-template-parameter' xml element node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to parse from.
 ///
@@ -5851,7 +5686,7 @@ build_non_type_tparameter(read_context&	ctxt,
 /// @return a pointer to a new instance of template_tparameter
 /// upon successful completion, a null pointer otherwise.
 static template_tparameter_sptr
-build_template_tparameter(read_context&	ctxt,
+build_template_tparameter(reader&	rdr,
 			  const xmlNodePtr	node,
 			  unsigned		index,
 			  template_decl_sptr	tdecl)
@@ -5873,7 +5708,7 @@ build_template_tparameter(read_context&	ctxt,
   // Bail out if no type with this ID exists.
   if (!type_id.empty()
       && !(dynamic_pointer_cast<template_tparameter>
-	   (ctxt.build_or_get_type_decl(type_id, true))))
+	   (rdr.build_or_get_type_decl(type_id, true))))
     abort();
 
   string name;
@@ -5881,12 +5716,12 @@ build_template_tparameter(read_context&	ctxt,
     name = xml::unescape_xml_string(CHAR_STR(s));
 
   location loc;
-  read_location(ctxt, node, loc);
+  read_location(rdr, node, loc);
 
   template_tparameter_sptr result(new template_tparameter(index, tdecl,
 							  name, loc));
-  maybe_set_artificial_location(ctxt, node, result);
-  ctxt.push_decl_to_current_scope(result, /*add_to_current_scope=*/true);
+  maybe_set_artificial_location(rdr, node, result);
+  rdr.push_decl_to_current_scope(result, /*add_to_current_scope=*/true);
 
   // Go parse template parameters that are children nodes
   int parm_index = 0;
@@ -5894,7 +5729,7 @@ build_template_tparameter(read_context&	ctxt,
        n;
        n = xmlNextElementSibling(n))
     if (shared_ptr<template_parameter> p =
-	build_template_parameter(ctxt, n, parm_index, result))
+	build_template_parameter(rdr, n, parm_index, result))
       {
 	result->add_template_parameter(p);
 	++parm_index;
@@ -5902,8 +5737,8 @@ build_template_tparameter(read_context&	ctxt,
 
   if (result)
     {
-      ctxt.key_type_decl(result, id);
-      ctxt.maybe_canonicalize_type(result, /*force_delay=*/false);
+      rdr.key_type_decl(result, id);
+      rdr.maybe_canonicalize_type(result, /*force_delay=*/false);
     }
 
   return result;
@@ -5912,7 +5747,7 @@ build_template_tparameter(read_context&	ctxt,
 /// Build a template parameter type from several possible xml elment
 /// nodes representing a serialized form a template parameter.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml element node to parse from.
 ///
@@ -5925,52 +5760,52 @@ build_template_tparameter(read_context&	ctxt,
 /// template_parameter upon successful completion, a null pointer
 /// otherwise.
 static template_parameter_sptr
-build_template_parameter(read_context&		ctxt,
+build_template_parameter(reader&		rdr,
 			 const xmlNodePtr	node,
 			 unsigned		index,
 			 template_decl_sptr	tdecl)
 {
   shared_ptr<template_parameter> r;
-  ((r = build_type_tparameter(ctxt, node, index, tdecl))
-   || (r = build_non_type_tparameter(ctxt, node, index, tdecl))
-   || (r = build_template_tparameter(ctxt, node, index, tdecl))
-   || (r = build_type_composition(ctxt, node, index, tdecl)));
+  ((r = build_type_tparameter(rdr, node, index, tdecl))
+   || (r = build_non_type_tparameter(rdr, node, index, tdecl))
+   || (r = build_template_tparameter(rdr, node, index, tdecl))
+   || (r = build_type_composition(rdr, node, index, tdecl)));
 
   return r;
 }
 
 /// Build a type from an xml node.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the xml node to build the type_base from.
 ///
 /// @return a pointer to the newly built type_base upon successful
 /// completion, a null pointer otherwise.
 static type_base_sptr
-build_type(read_context&	ctxt,
+build_type(reader&	rdr,
 	   const xmlNodePtr	node,
 	   bool		add_to_current_scope)
 {
   type_base_sptr t;
 
-  ((t = build_type_decl(ctxt, node, add_to_current_scope))
-   || (t = build_qualified_type_decl(ctxt, node, add_to_current_scope))
-   || (t = build_pointer_type_def(ctxt, node, add_to_current_scope))
-   || (t = build_reference_type_def(ctxt, node , add_to_current_scope))
-   || (t = build_function_type(ctxt, node, add_to_current_scope))
-   || (t = build_array_type_def(ctxt, node, add_to_current_scope))
-   || (t = build_enum_type_decl_if_not_suppressed(ctxt, node,
+  ((t = build_type_decl(rdr, node, add_to_current_scope))
+   || (t = build_qualified_type_decl(rdr, node, add_to_current_scope))
+   || (t = build_pointer_type_def(rdr, node, add_to_current_scope))
+   || (t = build_reference_type_def(rdr, node , add_to_current_scope))
+   || (t = build_function_type(rdr, node, add_to_current_scope))
+   || (t = build_array_type_def(rdr, node, add_to_current_scope))
+   || (t = build_enum_type_decl_if_not_suppressed(rdr, node,
 						  add_to_current_scope))
-   || (t = build_typedef_decl(ctxt, node, add_to_current_scope))
-   || (t = build_class_decl_if_not_suppressed(ctxt, node,
+   || (t = build_typedef_decl(rdr, node, add_to_current_scope))
+   || (t = build_class_decl_if_not_suppressed(rdr, node,
 					      add_to_current_scope))
-   || (t = build_union_decl_if_not_suppressed(ctxt, node,
+   || (t = build_union_decl_if_not_suppressed(rdr, node,
 					      add_to_current_scope)));
 
-  if (ctxt.tracking_non_reachable_types() && t)
+  if (rdr.tracking_non_reachable_types() && t)
     {
-      corpus_sptr abi = ctxt.get_corpus();
+      corpus_sptr abi = rdr.corpus();
       ABG_ASSERT(abi);
       bool is_non_reachable_type = false;
       read_is_non_reachable_type(node, is_non_reachable_type);
@@ -5981,263 +5816,263 @@ build_type(read_context&	ctxt,
   MAYBE_MAP_TYPE_WITH_TYPE_ID(t, node);
 
   if (t)
-    ctxt.maybe_canonicalize_type(t,/*force_delay=*/false );
+    rdr.maybe_canonicalize_type(t,/*force_delay=*/false );
   return t;
 }
 
 /// Parses 'type-decl' xml element.
 ///
-/// @param ctxt the parsing context.
+/// @param rdr the parsing context.
 ///
 /// @return true upon successful parsing, false otherwise.
 static decl_base_sptr
-handle_type_decl(read_context&	ctxt,
+handle_type_decl(reader&	rdr,
 		 xmlNodePtr	node,
 		 bool		add_to_current_scope)
 {
-  type_decl_sptr decl = build_type_decl(ctxt, node, add_to_current_scope);
+  type_decl_sptr decl = build_type_decl(rdr, node, add_to_current_scope);
   MAYBE_MAP_TYPE_WITH_TYPE_ID(decl, node);
   if (decl && decl->get_scope())
-    ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
+    rdr.maybe_canonicalize_type(decl, /*force_delay=*/false);
   return decl;
 }
 
 /// Parses 'namespace-decl' xml element.
 ///
-/// @param ctxt the parsing context.
+/// @param rdr the parsing context.
 ///
 /// @return true upon successful parsing, false otherwise.
 static decl_base_sptr
-handle_namespace_decl(read_context&	ctxt,
+handle_namespace_decl(reader&	rdr,
 		      xmlNodePtr	node,
 		      bool		add_to_current_scope)
 {
-  namespace_decl_sptr d = build_namespace_decl(ctxt, node,
+  namespace_decl_sptr d = build_namespace_decl(rdr, node,
 					       add_to_current_scope);
   return d;
 }
 
 /// Parse a qualified-type-def xml element.
 ///
-/// @param ctxt the parsing context.
+/// @param rdr the parsing context.
 ///
 /// @return true upon successful parsing, false otherwise.
 static decl_base_sptr
-handle_qualified_type_decl(read_context&	ctxt,
+handle_qualified_type_decl(reader&	rdr,
 			   xmlNodePtr		node,
 			   bool		add_to_current_scope)
 {
   qualified_type_def_sptr decl =
-    build_qualified_type_decl(ctxt, node,
+    build_qualified_type_decl(rdr, node,
 			      add_to_current_scope);
   MAYBE_MAP_TYPE_WITH_TYPE_ID(decl, node);
   if (decl && decl->get_scope())
-    ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
+    rdr.maybe_canonicalize_type(decl, /*force_delay=*/false);
   return decl;
 }
 
 /// Parse a pointer-type-decl element.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @return true upon successful completion, false otherwise.
 static decl_base_sptr
-handle_pointer_type_def(read_context&	ctxt,
+handle_pointer_type_def(reader&	rdr,
 			xmlNodePtr	node,
 			bool		add_to_current_scope)
 {
-  pointer_type_def_sptr decl = build_pointer_type_def(ctxt, node,
+  pointer_type_def_sptr decl = build_pointer_type_def(rdr, node,
 						      add_to_current_scope);
   MAYBE_MAP_TYPE_WITH_TYPE_ID(decl, node);
   if (decl && decl->get_scope())
-    ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
+    rdr.maybe_canonicalize_type(decl, /*force_delay=*/false);
   return decl;
 }
 
 /// Parse a reference-type-def element.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// reference_type_def is added to.
 static decl_base_sptr
-handle_reference_type_def(read_context& ctxt,
+handle_reference_type_def(reader& rdr,
 			  xmlNodePtr	node,
 			  bool		add_to_current_scope)
 {
-  reference_type_def_sptr decl = build_reference_type_def(ctxt, node,
+  reference_type_def_sptr decl = build_reference_type_def(rdr, node,
 							  add_to_current_scope);
   MAYBE_MAP_TYPE_WITH_TYPE_ID(decl, node);
   if (decl && decl->get_scope())
-    ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
+    rdr.maybe_canonicalize_type(decl, /*force_delay=*/false);
   return decl;
 }
 
 /// Parse a function-type element.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// function_type is added to.
 static type_base_sptr
-handle_function_type(read_context&	ctxt,
+handle_function_type(reader&	rdr,
 		     xmlNodePtr	node,
 		     bool		add_to_current_scope)
 {
-  function_type_sptr type = build_function_type(ctxt, node,
+  function_type_sptr type = build_function_type(rdr, node,
 						  add_to_current_scope);
   MAYBE_MAP_TYPE_WITH_TYPE_ID(type, node);
-  ctxt.maybe_canonicalize_type(type, /*force_delay=*/true);
+  rdr.maybe_canonicalize_type(type, /*force_delay=*/true);
   return type;
 }
 
 /// Parse a array-type-def element.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// array_type_def is added to.
 static decl_base_sptr
-handle_array_type_def(read_context&	ctxt,
+handle_array_type_def(reader&	rdr,
 		      xmlNodePtr	node,
 		      bool		add_to_current_scope)
 {
-  array_type_def_sptr decl = build_array_type_def(ctxt, node,
+  array_type_def_sptr decl = build_array_type_def(rdr, node,
 						  add_to_current_scope);
   MAYBE_MAP_TYPE_WITH_TYPE_ID(decl, node);
-  ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
+  rdr.maybe_canonicalize_type(decl, /*force_delay=*/false);
   return decl;
 }
 
 /// Parse an enum-decl element.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 static decl_base_sptr
-handle_enum_type_decl(read_context&	ctxt,
+handle_enum_type_decl(reader&	rdr,
 		      xmlNodePtr	node,
 		      bool		add_to_current_scope)
 {
   enum_type_decl_sptr decl =
-    build_enum_type_decl_if_not_suppressed(ctxt, node,
+    build_enum_type_decl_if_not_suppressed(rdr, node,
 					   add_to_current_scope);
   MAYBE_MAP_TYPE_WITH_TYPE_ID(decl, node);
   if (decl && decl->get_scope())
-    ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
+    rdr.maybe_canonicalize_type(decl, /*force_delay=*/false);
   return decl;
 }
 
 /// Parse a typedef-decl element.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 static decl_base_sptr
-handle_typedef_decl(read_context&	ctxt,
+handle_typedef_decl(reader&	rdr,
 		    xmlNodePtr		node,
 		    bool		add_to_current_scope)
 {
-  typedef_decl_sptr decl = build_typedef_decl(ctxt, node,
+  typedef_decl_sptr decl = build_typedef_decl(rdr, node,
 					      add_to_current_scope);
   MAYBE_MAP_TYPE_WITH_TYPE_ID(decl, node);
   if (decl && decl->get_scope())
-    ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
+    rdr.maybe_canonicalize_type(decl, /*force_delay=*/false);
   return decl;
 }
 
 /// Parse a var-decl element.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @param node the node to read & parse from.
 ///
 /// @param add_to_current_scope if set to yes, the resulting of this
 /// function is added to its current scope.
 static decl_base_sptr
-handle_var_decl(read_context&	ctxt,
+handle_var_decl(reader&	rdr,
 		xmlNodePtr	node,
 		bool		add_to_current_scope)
 {
-  decl_base_sptr decl = build_var_decl_if_not_suppressed(ctxt, node,
+  decl_base_sptr decl = build_var_decl_if_not_suppressed(rdr, node,
 							 add_to_current_scope);
-  ctxt.maybe_add_var_to_exported_decls(is_var_decl(decl));
+  rdr.maybe_add_var_to_exported_decls(is_var_decl(decl).get());
   return decl;
 }
 
 /// Parse a function-decl element.
 ///
-/// @param ctxt the context of the parsing
+/// @param rdr the context of the parsing
 ///
 /// @return true upon successful completion of the parsing, false
 /// otherwise.
 static decl_base_sptr
-handle_function_decl(read_context&	ctxt,
+handle_function_decl(reader&	rdr,
 		     xmlNodePtr	node,
 		     bool		add_to_current_scope)
 {
-  return build_function_decl_if_not_suppressed(ctxt, node, class_decl_sptr(),
+  return build_function_decl_if_not_suppressed(rdr, node, class_decl_sptr(),
 					       add_to_current_scope);
 }
 
 /// Parse a 'class-decl' xml element.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @return the resulting @ref class_decl built from the XML element
 /// upon successful completion of the parsing, nil otherwise.
 static decl_base_sptr
-handle_class_decl(read_context& ctxt,
+handle_class_decl(reader& rdr,
 		  xmlNodePtr	node,
 		  bool		add_to_current_scope)
 {
   class_decl_sptr decl =
-    build_class_decl_if_not_suppressed(ctxt, node, add_to_current_scope);
+    build_class_decl_if_not_suppressed(rdr, node, add_to_current_scope);
   MAYBE_MAP_TYPE_WITH_TYPE_ID(is_type(decl), node);
   if (decl && decl->get_scope())
-    ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
+    rdr.maybe_canonicalize_type(decl, /*force_delay=*/false);
   return decl;
 }
 
 /// Parse a 'union-decl' xml element.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @return the resulting @ref union_decl built from the XML element
 /// upon successful completion of the parsing, nil otherwise.
 static decl_base_sptr
-handle_union_decl(read_context& ctxt,
+handle_union_decl(reader& rdr,
 		  xmlNodePtr	node,
 		  bool		add_to_current_scope)
 {
   union_decl_sptr decl =
-    build_union_decl_if_not_suppressed(ctxt, node, add_to_current_scope);
+    build_union_decl_if_not_suppressed(rdr, node, add_to_current_scope);
   MAYBE_MAP_TYPE_WITH_TYPE_ID(is_type(decl), node);
   if (decl && decl->get_scope())
-    ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
+    rdr.maybe_canonicalize_type(decl, /*force_delay=*/false);
   return decl;
 }
 
 /// Parse a 'function-template-decl' xml element.
 ///
-/// @param ctxt the parsing context.
+/// @param rdr the parsing context.
 ///
 /// @return true upon successful completion of the parsing, false
 /// otherwise.
 static decl_base_sptr
-handle_function_tdecl(read_context&	ctxt,
+handle_function_tdecl(reader&	rdr,
 		      xmlNodePtr	node,
 		      bool		add_to_current_scope)
 {
-  function_tdecl_sptr d = build_function_tdecl(ctxt, node,
+  function_tdecl_sptr d = build_function_tdecl(rdr, node,
 					       add_to_current_scope);
   return d;
 }
 
 /// Parse a 'class-template-decl' xml element.
 ///
-/// @param ctxt the context of the parsing.
+/// @param rdr the context of the parsing.
 ///
 /// @return true upon successful completion, false otherwise.
 static decl_base_sptr
-handle_class_tdecl(read_context&	ctxt,
+handle_class_tdecl(reader&	rdr,
 		   xmlNodePtr		node,
 		   bool		add_to_current_scope)
 {
-  class_tdecl_sptr decl = build_class_tdecl(ctxt, node,
+  class_tdecl_sptr decl = build_class_tdecl(rdr, node,
 					    add_to_current_scope);
   return decl;
 }
@@ -6252,10 +6087,10 @@ handle_class_tdecl(read_context&	ctxt,
 /// @return the translation unit resulting from the parsing upon
 /// successful completion, or nil.
 translation_unit_sptr
-read_translation_unit_from_istream(istream* in, environment* env)
+read_translation_unit_from_istream(istream* in, environment& env)
 {
-  read_context read_ctxt(xml::new_reader_from_istream(in), env);
-  return read_translation_unit_from_input(read_ctxt);
+  reader read_rdr(xml::new_reader_from_istream(in), env);
+  return read_translation_unit_from_input(read_rdr);
 }
 template<typename T>
 struct array_deleter
@@ -6268,30 +6103,29 @@ struct array_deleter
 };//end array_deleter
 
 
-/// Create an xml_reader::read_context to read a native XML ABI file.
+/// Create an xml_reader::reader to read a native XML ABI file.
 ///
 /// @param path the path to the native XML file to read.
 ///
 /// @param env the environment to use.
 ///
 /// @return the created context.
-read_context_sptr
-create_native_xml_read_context(const string& path, environment *env)
+fe_iface_sptr
+create_abixml_reader(const string& path, environment& env)
 {
-  read_context_sptr result(new read_context(xml::new_reader_from_file(path),
-					    env));
-  corpus_sptr corp(new corpus(env));
+  reader_sptr result(new reader(xml::new_reader_from_file(path),
+				env));
+  corpus_sptr corp = result->corpus();
   corp->set_origin(corpus::NATIVE_XML_ORIGIN);
-  result->set_corpus(corp);
 #ifdef WITH_DEBUG_SELF_COMPARISON
-  if (env->self_comparison_debug_is_on())
-    env->set_self_comparison_debug_input(result->get_corpus());
+  if (env.self_comparison_debug_is_on())
+    env.set_self_comparison_debug_input(result->corpus());
 #endif
   result->set_path(path);
   return result;
 }
 
-/// Create an xml_reader::read_context to read a native XML ABI from
+/// Create an xml_reader::reader to read a native XML ABI from
 /// an input stream..
 ///
 /// @param in the input stream that contains the native XML file to read.
@@ -6299,28 +6133,20 @@ create_native_xml_read_context(const string& path, environment *env)
 /// @param env the environment to use.
 ///
 /// @return the created context.
-read_context_sptr
-create_native_xml_read_context(std::istream* in, environment* env)
+fe_iface_sptr
+create_abixml_reader(std::istream* in, environment& env)
 {
-  read_context_sptr result(new read_context(xml::new_reader_from_istream(in),
-					    env));
-  corpus_sptr corp(new corpus(env, ""));
+  reader_sptr result(new reader(xml::new_reader_from_istream(in),
+				env));
+  corpus_sptr corp = result->corpus();
   corp->set_origin(corpus::NATIVE_XML_ORIGIN);
-  result->set_corpus(corp);
 #ifdef WITH_DEBUG_SELF_COMPARISON
-  if (env->self_comparison_debug_is_on())
-    env->set_self_comparison_debug_input(result->get_corpus());
+  if (env.self_comparison_debug_is_on())
+    env.set_self_comparison_debug_input(result->corpus());
 #endif
   return result;
 }
 
-/// Getter for the path to the binary this @ref read_context is for.
-///
-/// @return the path to the binary the @ref read_context is for.
-const string&
-read_context_get_path(const read_context& ctxt)
-{return ctxt.get_path();}
-
 /// De-serialize an ABI corpus from an input XML document which root
 /// node is 'abi-corpus'.
 ///
@@ -6334,11 +6160,12 @@ read_context_get_path(const read_context& ctxt)
 /// @return the resulting corpus de-serialized from the parsing.  This
 /// is non-null iff the parsing resulted in a valid corpus.
 corpus_sptr
-read_corpus_from_native_xml(std::istream* in,
-			    environment* env)
+read_corpus_from_abixml(std::istream* in,
+			environment& env)
 {
-  read_context_sptr read_ctxt = create_native_xml_read_context(in, env);
-  return read_corpus_from_input(*read_ctxt);
+  fe_iface_sptr rdr = create_abixml_reader(in, env);
+  fe_iface::status sts;
+  return rdr->read_corpus(sts);
 }
 
 /// De-serialize an ABI corpus from an XML document file which root
@@ -6355,11 +6182,12 @@ read_corpus_from_native_xml(std::istream* in,
 /// @return the resulting corpus de-serialized from the parsing.  This
 /// is non-null if the parsing successfully resulted in a corpus.
 corpus_sptr
-read_corpus_from_native_xml_file(const string& path,
-				 environment* env)
+read_corpus_from_abixml_file(const string& path,
+			     environment& env)
 {
-  read_context_sptr read_ctxt = create_native_xml_read_context(path, env);
-  corpus_sptr corp = read_corpus_from_input(*read_ctxt);
+  fe_iface_sptr rdr = create_abixml_reader(path, env);
+  fe_iface::status sts;
+  corpus_sptr corp = rdr->read_corpus(sts);
   return corp;
 }
 
@@ -6377,15 +6205,17 @@ read_corpus_from_native_xml_file(const string& path,
 /// The function that stored the map in that file is
 /// write_canonical_type_ids.
 ///
-/// @param ctxt the read context to use.
+/// @param rdr the ABIXML reader to use.
 ///
 /// @param file_path the path to the file containing the type-ids <->
 /// canonical type mapping.
 ///
 /// @return true iff the loading was successful.
 bool
-load_canonical_type_ids(xml_reader::read_context& ctxt, const string &file_path)
+load_canonical_type_ids(fe_iface& iface, const string &file_path)
 {
+  xml_reader::reader& rdr = dynamic_cast<xml_reader::reader&>(iface)
+
   xmlDocPtr doc = xmlReadFile(file_path.c_str(), NULL, XML_PARSE_NOERROR);
   if (!doc)
     return false;
@@ -6443,7 +6273,7 @@ load_canonical_type_ids(xml_reader::read_context& ctxt, const string &file_path)
 	      // that are not canonicalized.  Look into function
 	      // hash_as_canonical_type_or_constant for the details.
 	      && v != 0xdeadbabe)
-	    ctxt.get_environment()->get_type_id_canonical_type_map()[id] = v;
+	    rdr.get_environment()->get_type_id_canonical_type_map()[id] = v;
 	}
     }
   return true;
diff --git a/src/abg-suppression-priv.h b/src/abg-suppression-priv.h
index 47e39e76..13d17059 100644
--- a/src/abg-suppression-priv.h
+++ b/src/abg-suppression-priv.h
@@ -404,59 +404,10 @@ bool
 suppression_matches_variable_name(const suppr::variable_suppression& s,
 				  const string& var_name);
 
-
 bool
 suppression_matches_variable_sym_name(const suppr::variable_suppression& s,
 				      const string& var_linkage_name);
 
-/// Test if a given function denoted by its name and linkage name is
-/// suppressed by any of the suppression specifications associated to
-/// a given read context used to build the current internal
-/// representation of ABI corpus.
-///
-/// @param ctxt the reading context of interest.
-///
-/// @param fn_name the name of the function that a specification can
-/// match.
-///
-/// @param fn_linkage_name the linkage name of the function that a
-/// specification can match.
-///
-/// @param require_drop_property if set to "true", tests if the
-/// function is suppressed and if its representation is dropped from
-/// the ABI corpus being built.  Otherwise, if set to "false", only
-/// test if the function is suppressed.
-///
-/// @return true iff at least one function specification matches a
-/// function with name @p fn_name or with linkage name @p
-/// fn_linkage_name.
-template <typename ReadContextType>
-bool
-function_is_suppressed(const ReadContextType&	ctxt,
-		       const string&		fn_name,
-		       const string&		fn_linkage_name,
-		       bool			require_drop_property = false)
-{
-  for (suppr::suppressions_type::const_iterator i =
-	 ctxt.get_suppressions().begin();
-       i != ctxt.get_suppressions().end();
-       ++i)
-    if (suppr::function_suppression_sptr suppr = is_function_suppression(*i))
-      {
-	if (require_drop_property && !(*i)->get_drops_artifact_from_ir())
-	  continue;
-	if (!fn_name.empty()
-	    && ctxt.suppression_matches_function_name(*suppr, fn_name))
-	  return true;
-	if (!fn_linkage_name.empty()
-	    && ctxt.suppression_matches_function_sym_name(*suppr,
-							  fn_linkage_name))
-	  return true;
-      }
-  return false;
-}
-// </function_suppression stuff>
-
 // <variable_suppression stuff>
 /// The type of the private data of the @ref variable_suppression
 /// type.
@@ -604,32 +555,6 @@ struct variable_suppression::priv
   }
 };// end class variable_supppression::priv
 
-template <typename ReadContextType>
-bool
-variable_is_suppressed(const ReadContextType&	ctxt,
-		       const string&		var_name,
-		       const string&		var_linkage_name,
-		       bool			require_drop_property = false)
-{
-  for (suppr::suppressions_type::const_iterator i =
-	 ctxt.get_suppressions().begin();
-       i != ctxt.get_suppressions().end();
-       ++i)
-    if (suppr::variable_suppression_sptr suppr = is_variable_suppression(*i))
-      {
-	if (require_drop_property && !(*i)->get_drops_artifact_from_ir())
-	  continue;
-	if (!var_name.empty()
-	    && ctxt.suppression_matches_variable_name(*suppr, var_name))
-	  return true;
-	if (!var_linkage_name.empty()
-	    && ctxt.suppression_matches_variable_sym_name(*suppr,
-							  var_linkage_name))
-	  return true;
-      }
-  return false;
-}
-
 // </variable_suppression stuff>
 
 // <type_suppression stuff>
@@ -777,110 +702,6 @@ suppression_matches_type_name_or_location(const type_suppression& s,
 					  const string& type_name,
 					  const location& type_location);
 
-/// Test if a type (designated by its name and location) is suppressed
-/// by at least one suppression specification associated with a given
-/// read context.
-///
-/// @param ctxt the read context to consider.
-///
-/// @param type_name the name of the type to consider.
-///
-/// @param type_location the location of the type to consider.
-///
-/// @param require_drop_property if set to "true", tests if the type
-/// is suppressed and if its representation is dropped from the ABI
-/// corpus being built.  Otherwise, if set to "false", only test if
-/// the type is suppressed.
-///
-/// @return true iff at least one type specification matches a type
-/// with name @p type_name and with location @p type_location.
-template <typename ReadContextType>
-bool
-type_is_suppressed(const ReadContextType&	ctxt,
-		   const string&		type_name,
-		   const location&		type_location)
-{
-  bool type_is_private = false;
-  return type_is_suppressed(ctxt, type_name, type_location, type_is_private);
-}
-
-/// Test if a type (designated by its name and location) is suppressed
-/// by at least one suppression specification associated with a given
-/// read context.
-///
-/// @param ctxt the read context to consider.
-///
-/// @param type_name the name of the type to consider.
-///
-/// @param type_location the location of the type to consider.
-///
-/// @param type_is_private out parameter. If the type is suppressed
-/// because it's private then this out parameter is set to true.
-///
-/// @param require_drop_property if set to "true", tests if the type
-/// is suppressed and if its representation is dropped from the ABI
-/// corpus being built.  Otherwise, if set to "false", only test if
-/// the type is suppressed.
-///
-/// @return true iff at least one type specification matches a type
-/// with name @p type_name and with location @p type_location.
-template <typename ReadContextType>
-bool
-type_is_suppressed(const ReadContextType&	ctxt,
-		   const string&		type_name,
-		   const location&		type_location,
-		   bool&			type_is_private,
-		   bool require_drop_property = false)
-{
-  for (suppr::suppressions_type::const_iterator i =
-	 ctxt.get_suppressions().begin();
-       i != ctxt.get_suppressions().end();
-       ++i)
-    if (suppr::type_suppression_sptr suppr = is_type_suppression(*i))
-      {
-	if (require_drop_property && !(*i)->get_drops_artifact_from_ir())
-	  continue;
-	if (ctxt.suppression_matches_type_name_or_location(*suppr, type_name,
-							   type_location))
-	  {
-	    if (is_private_type_suppr_spec(*suppr))
-	      type_is_private = true;
-
-	    return true;
-	  }
-      }
-
-  type_is_private = false;
-  return false;
-}
-
-/// Test if a given ELF symbol is suppressed by a suppression
-/// specification.
-///
-/// @param ctxt the read context to use.
-///
-/// @param sym_name the name of the symbol to consider.
-///
-/// @param sym_type the type of the symbol to consider.
-///
-/// @return true iff the elf symbol denoted by @p sym_name and @p
-/// sym_type is suppressed.
-template<typename ReadContextType>
-bool
-is_elf_symbol_suppressed(const ReadContextType& ctxt,
-			 const string& sym_name,
-			 elf_symbol::type sym_type)
-{
-  if (elf_symbol_is_function(sym_type))
-    return suppr::function_is_suppressed(ctxt, /*fn_name=*/"",
-					 /*symbol_name=*/sym_name);
-  else if (elf_symbol_is_variable(sym_type))
-    return suppr::variable_is_suppressed(ctxt, /*var_name=*/"",
-					 /*symbol_name=*/sym_name);
-
-  return false;
-}
-
 // </type_suppression stuff>
 
 }// end namespace suppr
diff --git a/src/abg-suppression.cc b/src/abg-suppression.cc
index 21b8ec6a..07fe47f4 100644
--- a/src/abg-suppression.cc
+++ b/src/abg-suppression.cc
@@ -23,6 +23,7 @@ ABG_BEGIN_EXPORT_DECLARATIONS
 #include "abg-comp-filter.h"
 #include "abg-suppression.h"
 #include "abg-tools-utils.h"
+#include "abg-fe-iface.h"
 
 ABG_END_EXPORT_DECLARATIONS
 // </headers defining libabigail's API>
@@ -2932,78 +2933,6 @@ operator|(function_suppression::change_kind l,
       (static_cast<unsigned>(l) | static_cast<unsigned>(r));
 }
 
-  /// Test whether if a given function suppression matches a function
-  /// designated by a regular expression that describes its name.
-  ///
-  /// @param s the suppression specification to evaluate to see if it
-  /// matches a given function name.
-  ///
-  /// @param fn_name the name of the function of interest.  Note that
-  /// this name must be *non* qualified.
-  ///
-  /// @return true iff the suppression specification @p s matches the
-  /// function whose name is @p fn_name.
-bool
-suppression_matches_function_name(const suppr::function_suppression& s,
-				  const string& fn_name)
-{
-  if (regex_t_sptr regexp = s.priv_->get_name_regex())
-    {
-      if (!regex::match(regexp, fn_name))
-	return false;
-    }
-  else if (regex_t_sptr regexp = s.priv_->get_name_not_regex())
-    {
-      if (regex::match(regexp, fn_name))
-	return false;
-    }
-  else if (s.priv_->name_.empty())
-    return false;
-  else // if (!s.priv_->name_.empty())
-    {
-      if (s.priv_->name_ != fn_name)
-	return false;
-    }
-
-  return true;
-}
-
-/// Test whether if a given function suppression matches a function
-/// designated by a regular expression that describes its linkage
-/// name (symbol name).
-///
-/// @param s the suppression specification to evaluate to see if it
-/// matches a given function linkage name
-///
-/// @param fn_linkage_name the linkage name of the function of interest.
-///
-/// @return true iff the suppression specification @p s matches the
-/// function whose linkage name is @p fn_linkage_name.
-bool
-suppression_matches_function_sym_name(const suppr::function_suppression& s,
-				      const string& fn_linkage_name)
-{
-  if (regex_t_sptr regexp = s.priv_->get_symbol_name_regex())
-    {
-      if (!regex::match(regexp, fn_linkage_name))
-	return false;
-    }
-  else if (regex_t_sptr regexp = s.priv_->get_symbol_name_not_regex())
-    {
-      if (regex::match(regexp, fn_linkage_name))
-	return false;
-    }
-  else if (s.priv_->symbol_name_.empty())
-    return false;
-  else // if (!s.priv_->symbol_name_.empty())
-    {
-      if (s.priv_->symbol_name_ != fn_linkage_name)
-	return false;
-    }
-
-  return true;
-}
-
 /// Test if a variable suppression matches a variable denoted by its name.
 ///
 /// @param s the variable suppression to consider.
@@ -4239,6 +4168,43 @@ read_variable_suppression(const ini::config::section& section)
   return result;
 }
 
+/// Test if a given variable is suppressed by at least one suppression
+/// specification among a vector of suppression specifications.
+///
+/// @param supprs the vector of suppression specifications to consider.
+///
+/// @param var_name the name of the variable to consider.
+///
+/// @param var_linkage_name the linkage name of the variable to consider.
+///
+/// @param require_drop_property if yes, then only suppression
+/// specifications that require that the variable be dropped from the
+/// internal representation are taking into account.
+///
+/// @return true if there is at least one suppression specification in
+/// @p supprs which matches a variable named @p var_name, OR a
+/// variable which linkage name is @p var_linkage_name.
+bool
+variable_is_suppressed(const suppr::suppressions_type& supprs,
+		       const string&		var_name,
+		       const string&		var_linkage_name,
+		       bool			require_drop_property)
+{
+  for (auto i : supprs)
+    if (suppr::variable_suppression_sptr suppr = is_variable_suppression(i))
+      {
+	if (require_drop_property && !i->get_drops_artifact_from_ir())
+	  continue;
+	if (!var_name.empty()
+	    && suppression_matches_variable_name(*suppr, var_name))
+	  return true;
+	if (!var_linkage_name.empty()
+	    && suppression_matches_variable_sym_name(*suppr,
+						     var_linkage_name))
+	  return true;
+      }
+  return false;
+}
 // </variable_suppression stuff>
 
 // <file_suppression stuff>
@@ -4501,7 +4467,374 @@ is_private_type_suppr_spec(const suppression_sptr& s)
   return (type_suppr
 	  && type_suppr->get_label() == get_private_types_suppr_spec_label());
 }
-
 // </file_suppression stuff>
+
+/// Test if a given suppression specification can match an ABI
+/// artifact coming from the corpus being analyzed by a given
+/// front-end interface.
+///
+/// @param fe the front-end to consider.
+///
+/// @param s the suppression speficication to consider.
+///
+/// @return true if the suppression specification @p s CAN patch ABI
+/// artifacts coming from the ABI corpus being analyzed by the
+/// front-end @p fe.
+bool
+suppression_can_match(const fe_iface& fe,
+		      const suppression_base& s)
+{
+  if (!s.priv_->matches_soname(fe.dt_soname()))
+    if (s.has_soname_related_property())
+      // The suppression has some SONAME related properties, but
+      // none of them match the SONAME of the current binary.  So
+      // the suppression cannot match the current binary.
+      return false;
+
+  if (!s.priv_->matches_binary_name(fe.corpus_path()))
+    if (s.has_file_name_related_property())
+      // The suppression has some file_name related properties, but
+      // none of them match the file name of the current binary.  So
+      // the suppression cannot match the current binary.
+      return false;
+
+  return true;
+}
+
+/// Test if a given function is suppressed by a suppression
+/// specification.
+///
+/// @param fe the front-end to consider.
+///
+/// @param s the suppression specification to consider.
+///
+/// @param fn_name the name of the function to consider.
+///
+/// @return true iff the suppression specification @p s matches the
+/// function which name is @p fn_name.
+bool
+suppression_matches_function_name(const fe_iface& fe,
+				  const suppr::function_suppression& s,
+				  const string& fn_name)
+{
+  if (!suppression_can_match(fe, s))
+    return false;
+
+  if (regex::regex_t_sptr regexp = s.priv_->get_name_regex())
+    {
+      if (!regex::match(regexp, fn_name))
+	return false;
+    }
+  else if (regex::regex_t_sptr regexp = s.priv_->get_name_not_regex())
+    {
+      if (regex::match(regexp, fn_name))
+	return false;
+    }
+  else if (s.priv_->name_.empty())
+    return false;
+  else // if (!s.priv_->name_.empty())
+    {
+      if (s.priv_->name_ != fn_name)
+	return false;
+    }
+
+  return true;
+}
+
+/// Test if a given function is suppressed by a suppression
+/// specification.
+///
+/// @param fe the front-end to consider.
+///
+/// @param s the suppression specification to consider.
+///
+/// @param fn_linkage_name the linkage name of the function to
+/// consider.
+///
+/// @return true iff the suppression specification @p s matches the
+/// function which linkage name is @p fn_linkage_name.
+bool
+suppression_matches_function_sym_name(const fe_iface& fe,
+				      const suppr::function_suppression& s,
+				      const string& fn_linkage_name)
+{
+  if (!suppression_can_match(fe, s))
+    return false;
+
+  if (regex::regex_t_sptr regexp = s.priv_->get_symbol_name_regex())
+    {
+      if (!regex::match(regexp, fn_linkage_name))
+	return false;
+    }
+  else if (regex::regex_t_sptr regexp = s.priv_->get_symbol_name_not_regex())
+    {
+      if (regex::match(regexp, fn_linkage_name))
+	return false;
+    }
+  else if (s.priv_->symbol_name_.empty())
+    return false;
+  else // if (!s.priv_->symbol_name_.empty())
+    {
+      if (s.priv_->symbol_name_ != fn_linkage_name)
+	return false;
+    }
+
+  return true;
+}
+
+/// Test if a suppression specification matches a variable of a given
+/// name, in the context of a given front-end.
+///
+/// @param fe the front-end to consider.
+///
+/// @param s the variable suppression specification to consider.
+///
+/// @param var_name the name of the variable to consider.
+///
+/// @return true iff the suppression specification @p s matches the
+/// variable which name is @p var_name.
+bool
+suppression_matches_variable_name(const fe_iface& fe,
+				  const suppr::variable_suppression& s,
+				  const string& var_name)
+{
+  if (!suppression_can_match(fe, s))
+    return false;
+
+  return suppression_matches_variable_name(s, var_name);
+}
+
+/// Test if a suppression specification matches a variable which ELF
+/// symbol has a given name, in the context of a given front-end.
+///
+/// @param fe the front-end to consider.
+///
+/// @param s the variable suppression specification to consider.
+///
+/// @param var_linkage_name the name of the ELF symbol of the variable
+/// to consider.
+///
+/// @return true iff the suppression specification @p s matches the
+/// variable which ELF symbol name is @p var_linkage_name.
+bool
+suppression_matches_variable_sym_name(const fe_iface& fe,
+				      const suppr::variable_suppression& s,
+				      const string& var_linkage_name)
+{
+  if (!suppression_can_match(fe, s))
+    return false;
+
+  return suppression_matches_variable_sym_name(s, var_linkage_name);
+}
+
+/// Test if a suppression specification matches a type designated by
+/// its name and source location, in the context of a given front-end.
+///
+/// @param fe the front-end to consider.
+///
+/// @param s the suppression specification to consider.
+///
+/// @param type_name the name of the type to consider.
+///
+/// @param type_location the source location of the type designated by
+/// @p type_name.
+///
+/// @return true iff the suppression @p s matches the type designated
+/// by @p type_name at source location @type_location.
+bool
+suppression_matches_type_name_or_location(const fe_iface& fe,
+					  const suppr::type_suppression& s,
+					  const string& type_name,
+					  const location& type_location)
+{
+  if (!suppression_can_match(fe, s))
+    return false;
+
+  return suppression_matches_type_name_or_location(s, type_name,
+						   type_location);
+}
+
+/// Test if an ELF symbol is suppressed by at least one of the
+/// suppression specifications associated with a given front-end.
+///
+/// The function looks for each suppression specification provided to
+/// a given libabigail front-end and analyzes them to see if they
+/// match a given ELF symbol.
+///
+/// @param fe the front-end to consider.
+///
+/// @param symbol the ELF symbol to consider.
+///
+/// @return true iff the symbol @p symbol is matched by at least a
+/// suppression specification associated with the front-end @p fe.
+bool
+is_elf_symbol_suppressed(const fe_iface& fe,
+			 const elf_symbol_sptr& symbol)
+{
+  if (elf_symbol_is_function(symbol->get_type()))
+    return is_function_suppressed(fe, /*fn_name=*/"",
+				  /*symbol_name=*/symbol->get_name());
+  else if (elf_symbol_is_variable(symbol->get_type()))
+    return is_variable_suppressed(fe, /*var_name=*/"",
+				  /*symbol_name=*/symbol->get_name());
+  return false;
+}
+
+/// Test if an ELF symbol is suppressed by at least one of the
+/// suppression specifications associated with a given front-end.
+///
+/// The function looks for each suppression specification provided to
+/// a given libabigail front-end and analyzes them to see if they
+/// match a given ELF symbol, designated by its name and kind.
+///
+/// @param fe the front-end to consider.
+///
+/// @param sym_name the name of the symbol to consider.
+///
+/// @return true iff the symbol denoted by @p sym_name, of kind @p
+/// sym_type, is matched by at least a suppression specification
+/// associated with the front-end @p fe.
+bool
+is_elf_symbol_suppressed(const fe_iface& fe,
+			 const string& sym_name,
+			 elf_symbol::type sym_type)
+{
+  if (elf_symbol_is_function(sym_type))
+    return is_function_suppressed(fe, /*fn_name=*/"",
+				  /*symbol_name=*/sym_name);
+  else if (elf_symbol_is_variable(sym_type))
+    return is_variable_suppressed(fe, /*var_name=*/"",
+				  /*symbol_name=*/sym_name);
+  return false;
+}
+
+/// Test if a function is matched by at least one suppression
+/// specification associated with a given front-end.
+///
+/// The function is designated by its name and its linkage_name.
+///
+/// @param fe the front-end to consider.
+///
+/// @param fn_name the name of the function to consider.
+///
+/// @param fn_linkage_name the linkage name of the function to
+/// consider.
+///
+/// @param require_drop_property if true, this function requires the
+/// suppression specification to contain the "drop" property to match
+/// the function.
+///
+/// @return true iff the function is matched by at least one
+/// suppression specification coming from the front-end.
+bool
+is_function_suppressed(const fe_iface&	fe,
+		       const string&	fn_name,
+		       const string&	fn_linkage_name,
+		       bool		require_drop_property)
+{
+  for (auto i : fe.suppressions())
+    if (suppr::function_suppression_sptr suppr = is_function_suppression(i))
+      {
+	if (require_drop_property && !i->get_drops_artifact_from_ir())
+	  continue;
+	if (!fn_name.empty()
+	    && suppression_matches_function_name(fe, *suppr, fn_name))
+	  return true;
+	if (!fn_linkage_name.empty()
+	    && suppression_matches_function_sym_name(fe, *suppr,
+						     fn_linkage_name))
+	  return true;
+      }
+  return false;
+}
+
+/// Test if a variable is matched by at least one suppression
+/// specification associated with a given front-end.
+///
+/// The variable is designated by its name and its linkage_name.
+///
+/// @param fe the front-end to consider.
+///
+/// @param var_name the name of the variable to consider.
+///
+/// @param var_linkage_name the linkage name of the variable to
+/// consider.
+///
+/// @param require_drop_property if true, this variable requires the
+/// suppression specification to contain the "drop" property to match
+/// the function.
+///
+/// @return true iff the variable is matched by at least one
+/// suppression specification coming from the front-end.
+bool
+is_variable_suppressed(const fe_iface&	fe,
+		       const string&	var_name,
+		       const string&	var_linkage_name,
+		       bool		require_drop_property)
+{
+  for (auto i : fe.suppressions())
+    if (suppr::variable_suppression_sptr suppr = is_variable_suppression(i))
+      {
+	if (require_drop_property && !i->get_drops_artifact_from_ir())
+	  continue;
+	if (!var_name.empty()
+	    && suppression_matches_variable_name(fe, *suppr, var_name))
+	  return true;
+	if (!var_linkage_name.empty()
+	    && suppression_matches_variable_sym_name(fe, *suppr,
+						     var_linkage_name))
+	  return true;
+      }
+  return false;
+}
+
+/// Test if a type is matched by at least one suppression
+/// specification associated with a given front-end.
+///
+/// The type is designated by its name and its source location.
+///
+/// @param fe the front-end to consider.
+///
+/// @param type_name the name of the type to consider.
+///
+/// @param type_location the source location of the type.
+///
+/// @param type_is_private output parameter.  This is set to true if
+/// the type was matched by one suppression specification, and if the
+/// suppression was for private types.
+///
+/// @param require_drop_property if true, this type requires the
+/// suppression specification to contain the "drop" property to match
+/// the type.
+///
+/// @return true iff the type is matched by at least one suppression
+/// specification coming from the front-end.
+bool
+is_type_suppressed(const fe_iface&	fe,
+		   const string&	type_name,
+		   const location&	type_location,
+		   bool&		type_is_private,
+		   bool		require_drop_property)
+{
+  for (auto i : fe.suppressions())
+    if (suppr::type_suppression_sptr suppr = is_type_suppression(i))
+      {
+	if (require_drop_property && !i->get_drops_artifact_from_ir())
+	  continue;
+	if (suppression_matches_type_name_or_location(fe, *suppr,
+						      type_name,
+						      type_location))
+	  {
+	    if (is_private_type_suppr_spec(*suppr))
+	      type_is_private = true;
+
+	    return true;
+	  }
+      }
+
+  type_is_private = false;
+  return false;
+}
+
 }// end namespace suppr
 } // end namespace abigail
diff --git a/src/abg-symtab-reader.cc b/src/abg-symtab-reader.cc
index 606c96a2..219ab6c6 100644
--- a/src/abg-symtab-reader.cc
+++ b/src/abg-symtab-reader.cc
@@ -139,11 +139,10 @@ static struct
 /// not completed
 symtab_ptr
 symtab::load(Elf*	      elf_handle,
-	     ir::environment* env,
+	     const ir::environment& env,
 	     symbol_predicate is_suppressed)
 {
   ABG_ASSERT(elf_handle);
-  ABG_ASSERT(env);
 
   symtab_ptr result(new symtab);
   if (!result->load_(elf_handle, env, is_suppressed))
@@ -201,7 +200,7 @@ symtab::symtab()
 /// @return true if the load succeeded
 bool
 symtab::load_(Elf*	       elf_handle,
-	      ir::environment* env,
+	      const ir::environment& env,
 	      symbol_predicate is_suppressed)
 {
   GElf_Ehdr ehdr_mem;
diff --git a/src/abg-symtab-reader.h b/src/abg-symtab-reader.h
index 384d757f..4d90c302 100644
--- a/src/abg-symtab-reader.h
+++ b/src/abg-symtab-reader.h
@@ -243,7 +243,7 @@ public:
 
   static symtab_ptr
   load(Elf*		elf_handle,
-       ir::environment* env,
+       const ir::environment& env,
        symbol_predicate is_suppressed = NULL);
 
   static symtab_ptr
@@ -283,7 +283,9 @@ private:
   addr_symbol_map_type entry_addr_symbol_map_;
 
   bool
-  load_(Elf* elf_handle, ir::environment* env, symbol_predicate is_suppressed);
+  load_(Elf* elf_handle,
+	const ir::environment& env,
+	symbol_predicate is_suppressed);
 
   bool
   load_(string_elf_symbols_map_sptr function_symbol_map,
diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc
index fe9ebc72..08b581be 100644
--- a/src/abg-tools-utils.cc
+++ b/src/abg-tools-utils.cc
@@ -405,6 +405,56 @@ is_regular_file(const string& path)
   return false;
 }
 
+/// Test if an ELF file has DWARF debug info.
+///
+/// This function supports split debug info files as well.
+///
+/// @param elf_file_path the path to the ELF file to consider.
+///
+/// @param debug_info_root a vector of pointer to directory to look
+/// for debug info, in case the file is associated to split debug
+/// info.  If there is no split debug info then this vector can be
+/// empty.  Note that convert_char_stars_to_char_star_stars() can be
+/// used to ease the construction of this vector.
+///
+/// @return true iff the ELF file at @elf_file_path is an ELF file
+/// that contains debug info.
+bool
+file_has_dwarf_debug_info(const string& elf_file_path,
+			  const vector<char**>& debug_info_root_paths)
+{
+  if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
+    return false;
+
+  environment env;
+  elf_reader::reader r(elf_file_path,
+		       debug_info_root_paths,
+		       env);
+
+  if (r.dwarf_debug_info())
+    return true;
+
+  return false;
+}
+
+bool
+file_has_ctf_debug_info(const string& elf_file_path,
+			const vector<char**>& debug_info_root_paths)
+{
+    if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
+    return false;
+
+  environment env;
+  elf_reader::reader r(elf_file_path,
+		       debug_info_root_paths,
+		       env);
+
+  if (r.find_ctf_section())
+    return true;
+
+  return false;
+}
+
 /// Tests if a given path is a directory or a symbolic link to a
 /// directory.
 ///
@@ -2211,7 +2261,7 @@ find_file_under_dir(const string& root_dir,
 ///
 /// @param opts the options to consider.
 static void
-load_generate_apply_suppressions(dwarf_reader::read_context &read_ctxt,
+load_generate_apply_suppressions(elf_based_reader &rdr,
 				 vector<string>& suppr_paths,
 				 vector<string>& kabi_whitelist_paths,
 				 suppressions_type& supprs)
@@ -2229,7 +2279,7 @@ load_generate_apply_suppressions(dwarf_reader::read_context &read_ctxt,
       supprs.insert(supprs.end(), wl_suppr.begin(), wl_suppr.end());
     }
 
-  abigail::dwarf_reader::add_read_context_suppressions(read_ctxt, supprs);
+  rdr.add_suppressions(supprs);
 }
 
 /// Test if an FTSENT pointer (resulting from fts_read) represents the
@@ -2537,21 +2587,21 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
                                 suppressions_type&  supprs,
                                 bool                verbose,
                                 timer&              t,
-                                environment_sptr&   env)
+                                environment&        env)
 {
   if (!(origin & corpus::DWARF_ORIGIN))
     return;
 
-  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
-  dwarf_reader::read_context_sptr ctxt;
-  ctxt =
-   dwarf_reader::create_read_context(vmlinux, di_roots, env.get(),
-                                     /*read_all_types=*/false,
-                                     /*linux_kernel_mode=*/true);
-  dwarf_reader::set_do_log(*ctxt, verbose);
+  abigail::fe_iface::status status = abigail::fe_iface::STATUS_OK;
+  elf_based_reader_sptr rdr =
+    dwarf_reader::create_dwarf_reader(vmlinux, di_roots, env,
+				      /*read_all_types=*/false,
+				      /*linux_kernel_mode=*/true);
+  ABG_ASSERT(rdr);
+  rdr->options().do_log = verbose;
 
   t.start();
-  load_generate_apply_suppressions(*ctxt, suppr_paths,
+  load_generate_apply_suppressions(*rdr, suppr_paths,
                                    kabi_wl_paths, supprs);
   t.stop();
 
@@ -2560,9 +2610,9 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
      << t
      << "\n";
 
-  group.reset(new corpus_group(env.get(), root));
+  group.reset(new corpus_group(env, root));
 
-  set_read_context_corpus_group(*ctxt, group);
+  rdr->corpus_group(group);
 
   if (verbose)
     std::cerr << "reading kernel binary '"
@@ -2570,7 +2620,7 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
 
   // Read the vmlinux corpus and add it to the group.
   t.start();
-  read_and_add_corpus_to_group_from_elf(*ctxt, *group, status);
+  rdr->read_and_add_corpus_to_group(*group, status);
   t.stop();
 
   if (verbose)
@@ -2595,18 +2645,17 @@ maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
          << "/" << total_nb_modules
          << ") ... " << std::flush;
 
-      reset_read_context(ctxt, *m, di_roots, env.get(),
-                         /*read_all_types=*/false,
-                         /*linux_kernel_mode=*/true);
+      dwarf_reader::reset_dwarf_reader(*rdr, *m, di_roots,
+				       /*read_all_types=*/false,
+				       /*linux_kernel_mode=*/true);
 
-      load_generate_apply_suppressions(*ctxt, suppr_paths,
+      load_generate_apply_suppressions(*rdr, suppr_paths,
                                        kabi_wl_paths, supprs);
 
-      set_read_context_corpus_group(*ctxt, group);
+      rdr->corpus_group(group);
 
       t.start();
-      read_and_add_corpus_to_group_from_elf(*ctxt,
-                                            *group, status);
+      rdr->read_and_add_corpus_to_group(*group, status);
       t.stop();
       if (verbose)
         std::cerr << "module '"
@@ -2652,16 +2701,18 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
                               vector<char**>&     di_roots,
                               bool                verbose,
                               timer&              t,
-                              environment_sptr&   env)
+                              environment&        env)
 {
   if (!(origin & corpus::CTF_ORIGIN))
     return;
 
-  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
-  ctf_reader::read_context_sptr ctxt;
-  ctxt = ctf_reader::create_read_context(vmlinux, di_roots, env.get());
-  group.reset(new corpus_group(env.get(), root));
-  set_read_context_corpus_group(*ctxt, group);
+  abigail::fe_iface::status status = abigail::fe_iface::STATUS_OK;
+  elf_based_reader_sptr rdr =
+    ctf_reader::create_ctf_reader(vmlinux, di_roots, env);
+  ABG_ASSERT(rdr);
+
+  group.reset(new corpus_group(env, root));
+  rdr->corpus_group(group);
 
   if (verbose)
     std::cerr << "reading kernel binary '"
@@ -2669,7 +2720,7 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
 
   // Read the vmlinux corpus and add it to the group.
   t.start();
-  read_and_add_corpus_to_group_from_elf(ctxt.get(), *group, status);
+  rdr->read_and_add_corpus_to_group(*group, status);
   t.stop();
 
   if (verbose)
@@ -2694,12 +2745,11 @@ maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
          << "/" << total_nb_modules
          << ") ... " << std::flush;
 
-      reset_read_context(ctxt, *m, di_roots, env.get());
-      set_read_context_corpus_group(*ctxt, group);
+      ctf_reader::reset_reader(*rdr, *m, di_roots);
+      rdr->corpus_group(group);
 
       t.start();
-      read_and_add_corpus_to_group_from_elf(ctxt.get(),
-                                            *group, status);
+      rdr->read_and_add_corpus_to_group(*group, status);
       t.stop();
       if (verbose)
         std::cerr << "module '"
@@ -2757,7 +2807,7 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
 					  vector<string>&	kabi_wl_paths,
 					  suppressions_type&	supprs,
 					  bool			verbose,
-					  environment_sptr&	env,
+					  environment&		env,
 					  corpus::origin	origin)
 {
   string vmlinux = vmlinux_path;
@@ -2800,6 +2850,53 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
   return group;
 }
 
+/// Create the best elf based reader (or front-end), given an ELF file.
+///
+/// This function looks into the ELF file.  If it contains DWARF debug
+/// info, then a DWARF Reader front-end is created and returned.
+/// Otherwise, if it contains CTF debug info, then a CTF Reader
+/// front-end is created and returned.
+///
+/// Otherwise, if the file contains no debug info or if the king of
+/// debug info is not yet recognized, a DWARF Reader front-end is
+/// created and returned.
+///
+/// @param elf_file_path a path to the ELF file to consider
+///
+/// @param debug_info_root_paths a vector of the paths where to look
+/// for debug info, if applicable.
+///
+/// @param env the environment to use for the front-end.
+///
+/// @return the ELF based Reader that is better adapted for the binary
+/// designated by @p elf_file_path.
+elf_based_reader_sptr
+create_best_elf_based_reader(const string& elf_file_path,
+			     const vector<char**>& debug_info_root_paths,
+			     environment& env)
+{
+  elf_based_reader_sptr result;
+  if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
+    return result;
+
+  if (file_has_dwarf_debug_info(elf_file_path, debug_info_root_paths))
+    result = dwarf_reader::create_dwarf_reader(elf_file_path,
+					       debug_info_root_paths,
+					       env);
+#ifdef WITH_CTF
+  else if (file_has_ctf_debug_info(elf_file_path, debug_info_root_paths))
+    result = ctf_reader::create_ctf_reader(elf_file_path,
+					   debug_info_root_paths,
+					   env);
+#endif
+  else
+    result = dwarf_reader::create_dwarf_reader(elf_file_path,
+					       debug_info_root_paths,
+					       env);
+
+  return result;
+}
+
 }//end namespace tools_utils
 
 using abigail::ir::function_decl;
diff --git a/src/abg-writer.cc b/src/abg-writer.cc
index dff8813a..1cffd77b 100644
--- a/src/abg-writer.cc
+++ b/src/abg-writer.cc
@@ -65,7 +65,7 @@ namespace xml_writer
 
 class id_manager
 {
-  const environment* m_env;
+  const environment& m_env;
   mutable unsigned long long m_cur_id;
 
   unsigned long long
@@ -73,11 +73,11 @@ class id_manager
   { return ++m_cur_id; }
 
 public:
-  id_manager(const environment* env)
+  id_manager(const environment& env)
     : m_env(env),
       m_cur_id(0) {}
 
-  const environment*
+  const environment&
   get_environment() const
   {return m_env;}
 
@@ -87,9 +87,8 @@ public:
   {
     ostringstream o;
     o << get_new_id();
-    const environment* env = get_environment();
-    ABG_ASSERT(env);
-    return env->intern(o.str());
+    const environment& env = get_environment();
+    return env.intern(o.str());
   }
 
   /// Return a unique string representing a numerical ID, prefixed by
@@ -101,9 +100,8 @@ public:
   {
     ostringstream o;
     o << prefix << get_new_id();
-    const environment* env = get_environment();
-    ABG_ASSERT(env);
-    return env->intern(o.str());
+    const environment& env = get_environment();
+    return env.intern(o.str());
   }
 };
 
@@ -207,7 +205,7 @@ typedef unordered_map<shared_ptr<class_tdecl>,
 
 class write_context
 {
-  const environment*			m_env;
+  const environment&			m_env;
   id_manager				m_id_manager;
   ostream*				m_ostream;
   bool					m_annotate;
@@ -243,7 +241,7 @@ public:
   /// @param env the enviroment we are operating from.
   ///
   /// @param os the output stream to write to.
-  write_context(const environment* env, ostream& os)
+  write_context(const environment& env, ostream& os)
     : m_env(env),
       m_id_manager(env),
       m_ostream(&os),
@@ -262,16 +260,13 @@ public:
   /// Getter of the environment we are operating from.
   ///
   /// @return the environment we are operating from.
-  const environment*
+  const environment&
   get_environment() const
   {return m_env;}
 
   const config&
   get_config() const
-  {
-    ABG_ASSERT(get_environment());
-    return get_environment()->get_config();
-  }
+  {return get_environment().get_config();}
 
   /// Getter for the current ostream
   ///
@@ -498,7 +493,7 @@ public:
 	    ++hash;
 	  std::ostringstream os;
 	  os << std::hex << std::setfill('0') << std::setw(8) << hash;
-	  return m_type_id_map[c] = c->get_environment()->intern(os.str());
+	  return m_type_id_map[c] = c->get_environment().intern(os.str());
 	}
       }
     ABG_ASSERT_NOT_REACHED;
@@ -808,7 +803,7 @@ public:
   {
     ABG_ASSERT(!is_type(decl));
     string repr = get_pretty_representation(decl, true);
-    interned_string irepr = decl->get_environment()->intern(repr);
+    interned_string irepr = decl->get_environment().intern(repr);
     return m_emitted_decls_set.find(irepr) != m_emitted_decls_set.end();
   }
 
@@ -819,7 +814,7 @@ public:
   record_decl_as_emitted(const decl_base_sptr& decl)
   {
     string repr = get_pretty_representation(decl, true);
-    interned_string irepr = decl->get_environment()->intern(repr);
+    interned_string irepr = decl->get_environment().intern(repr);
     m_emitted_decls_set.insert(irepr);
   }
 
@@ -2064,7 +2059,7 @@ write_decl_in_scope(const decl_base_sptr&	decl,
 ///
 /// @return the new @ref write_context object.
 write_context_sptr
-create_write_context(const environment *env,
+create_write_context(const environment& env,
 		     ostream& default_output_stream)
 {
   write_context_sptr ctxt(new write_context(env, default_output_stream));
@@ -3691,7 +3686,7 @@ write_class_decl(const class_decl_sptr& d,
     {
       type_base_wptrs_type result;
       canonical_type_sptr_set_type member_types;
-      const environment* env = ctxt.get_environment();
+      const environment& env = ctxt.get_environment();
 
       // We are looking at a decl-only class.  All decl-only classes
       // of a given name are equal.  But then the problem is that a
@@ -3708,7 +3703,7 @@ write_class_decl(const class_decl_sptr& d,
       //
       // So let's gather all the member-types of all the decl-only
       // classes of the fully-qualified name and emit them here.
-      if (lookup_decl_only_class_types(env->intern(decl->get_qualified_name()),
+      if (lookup_decl_only_class_types(env.intern(decl->get_qualified_name()),
 				       *decl->get_corpus(),
 				       result))
 	{
diff --git a/tests/data/test-read-ctf/test0.abi b/tests/data/test-read-ctf/test0.abi
index 7a250218..2129de41 100644
--- a/tests/data/test-read-ctf/test0.abi
+++ b/tests/data/test-read-ctf/test0.abi
@@ -1,4 +1,7 @@
 <abi-corpus version='2.1' path='data/test-read-ctf/test0'>
+  <elf-needed>
+    <dependency name='libc.so.6'/>
+  </elf-needed>
   <elf-function-symbols>
     <elf-symbol name='__libc_csu_fini' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='__libc_csu_init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
diff --git a/tests/data/test-read-ctf/test0.hash.abi b/tests/data/test-read-ctf/test0.hash.abi
index 09e76da1..e98c97db 100644
--- a/tests/data/test-read-ctf/test0.hash.abi
+++ b/tests/data/test-read-ctf/test0.hash.abi
@@ -1,4 +1,7 @@
 <abi-corpus version='2.1' path='data/test-read-ctf/test0'>
+  <elf-needed>
+    <dependency name='libc.so.6'/>
+  </elf-needed>
   <elf-function-symbols>
     <elf-symbol name='__libc_csu_fini' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='__libc_csu_init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
diff --git a/tests/data/test-read-ctf/test1.so.abi b/tests/data/test-read-ctf/test1.so.abi
index 40a434ba..4d0895a3 100644
--- a/tests/data/test-read-ctf/test1.so.abi
+++ b/tests/data/test-read-ctf/test1.so.abi
@@ -1,4 +1,7 @@
 <abi-corpus version='2.1' path='data/test-read-ctf/test1.so'>
+  <elf-needed>
+    <dependency name='libc.so.6'/>
+  </elf-needed>
   <elf-function-symbols>
     <elf-symbol name='fn' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
diff --git a/tests/data/test-read-ctf/test1.so.hash.abi b/tests/data/test-read-ctf/test1.so.hash.abi
index cbdd0dc9..89bbb528 100644
--- a/tests/data/test-read-ctf/test1.so.hash.abi
+++ b/tests/data/test-read-ctf/test1.so.hash.abi
@@ -1,4 +1,7 @@
 <abi-corpus version='2.1' path='data/test-read-ctf/test1.so'>
+  <elf-needed>
+    <dependency name='libc.so.6'/>
+  </elf-needed>
   <elf-function-symbols>
     <elf-symbol name='fn' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
diff --git a/tests/data/test-read-ctf/test2.so.abi b/tests/data/test-read-ctf/test2.so.abi
index 67f802f9..53001972 100644
--- a/tests/data/test-read-ctf/test2.so.abi
+++ b/tests/data/test-read-ctf/test2.so.abi
@@ -1,4 +1,7 @@
 <abi-corpus version='2.1' path='data/test-read-ctf/test2.so'>
+  <elf-needed>
+    <dependency name='libc.so.6'/>
+  </elf-needed>
   <elf-function-symbols>
     <elf-symbol name='bar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='foo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
diff --git a/tests/data/test-read-ctf/test2.so.hash.abi b/tests/data/test-read-ctf/test2.so.hash.abi
index 6bbf347e..84fcaa96 100644
--- a/tests/data/test-read-ctf/test2.so.hash.abi
+++ b/tests/data/test-read-ctf/test2.so.hash.abi
@@ -1,4 +1,7 @@
 <abi-corpus version='2.1' path='data/test-read-ctf/test2.so'>
+  <elf-needed>
+    <dependency name='libc.so.6'/>
+  </elf-needed>
   <elf-function-symbols>
     <elf-symbol name='bar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='foo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
diff --git a/tests/data/test-read-ctf/test3.so.abi b/tests/data/test-read-ctf/test3.so.abi
index 3d2f6326..25fe7685 100644
--- a/tests/data/test-read-ctf/test3.so.abi
+++ b/tests/data/test-read-ctf/test3.so.abi
@@ -1,4 +1,7 @@
-<abi-corpus version='2.1' path='data/test-read-common/test3.so'>
+<abi-corpus version='2.1' path='data/test-read-common/test3.so' soname='test3.so.1'>
+  <elf-needed>
+    <dependency name='libc.so.6'/>
+  </elf-needed>
   <elf-function-symbols>
     <elf-symbol name='__foo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='__foo__' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
diff --git a/tests/data/test-read-ctf/test3.so.hash.abi b/tests/data/test-read-ctf/test3.so.hash.abi
index 1c69e2e1..07dd9601 100644
--- a/tests/data/test-read-ctf/test3.so.hash.abi
+++ b/tests/data/test-read-ctf/test3.so.hash.abi
@@ -1,4 +1,7 @@
-<abi-corpus version='2.1' path='data/test-read-common/test3.so'>
+<abi-corpus version='2.1' path='data/test-read-common/test3.so' soname='test3.so.1'>
+  <elf-needed>
+    <dependency name='libc.so.6'/>
+  </elf-needed>
   <elf-function-symbols>
     <elf-symbol name='__foo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='__foo__' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
diff --git a/tests/data/test-read-ctf/test4.so.abi b/tests/data/test-read-ctf/test4.so.abi
index dc18e191..21241d30 100644
--- a/tests/data/test-read-ctf/test4.so.abi
+++ b/tests/data/test-read-ctf/test4.so.abi
@@ -1,4 +1,7 @@
 <abi-corpus version='2.1' path='data/test-read-common/test4.so'>
+  <elf-needed>
+    <dependency name='libc.so.6'/>
+  </elf-needed>
   <elf-function-symbols>
     <elf-symbol name='cpy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
diff --git a/tests/data/test-read-ctf/test4.so.hash.abi b/tests/data/test-read-ctf/test4.so.hash.abi
index dc428592..40ab7069 100644
--- a/tests/data/test-read-ctf/test4.so.hash.abi
+++ b/tests/data/test-read-ctf/test4.so.hash.abi
@@ -1,4 +1,7 @@
 <abi-corpus version='2.1' path='data/test-read-common/test4.so'>
+  <elf-needed>
+    <dependency name='libc.so.6'/>
+  </elf-needed>
   <elf-function-symbols>
     <elf-symbol name='cpy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
   </elf-function-symbols>
diff --git a/tests/print-diff-tree.cc b/tests/print-diff-tree.cc
index c0c7195a..a06b1d51 100644
--- a/tests/print-diff-tree.cc
+++ b/tests/print-diff-tree.cc
@@ -101,24 +101,24 @@ main(int argc, char* argv[])
 
   if (!opts.elf1.empty() && !opts.elf2.empty())
     {
-      elf_reader::status c1_status, c2_status;
+      fe_iface::status c1_status, c2_status;
       corpus_sptr c1, c2;
 
-      environment_sptr env(new environment);
+      environment env;
       vector<char**> di_roots;
-      c1 = dwarf_reader::read_corpus_from_elf(opts.elf1, di_roots, env.get(),
+      c1 = dwarf_reader::read_corpus_from_elf(opts.elf1, di_roots, env,
 					      /*load_all_types=*/false,
 					      c1_status);
-      if (c1_status != elf_reader::STATUS_OK)
+      if (c1_status != fe_iface::STATUS_OK)
 	{
 	  cerr << "Failed to read elf file " << opts.elf1 << "\n";
 	  return 1;
 	}
 
-      c2 = dwarf_reader::read_corpus_from_elf(opts.elf2, di_roots, env.get(),
+      c2 = dwarf_reader::read_corpus_from_elf(opts.elf2, di_roots, env,
 					      /*load_all_types=*/false,
 					      c2_status);
-      if (c2_status != elf_reader::STATUS_OK)
+      if (c2_status != fe_iface::STATUS_OK)
 	{
 	  cerr << "Failed to read elf file " << opts.elf2 << "\n";
 	  return 1;
diff --git a/tests/test-abidiff.cc b/tests/test-abidiff.cc
index 951b6d25..c703284a 100644
--- a/tests/test-abidiff.cc
+++ b/tests/test-abidiff.cc
@@ -171,9 +171,9 @@ using abigail::corpus_sptr;
 using abigail::corpus_group_sptr;
 using abigail::translation_unit;
 using abigail::translation_unit_sptr;
-using abigail::xml_reader::read_translation_unit_from_file;
-using abigail::xml_reader::read_corpus_from_native_xml_file;
-using abigail::xml_reader::read_corpus_group_from_native_xml_file;
+using abigail::abixml_reader::read_translation_unit_from_file;
+using abigail::abixml_reader::read_corpus_from_abixml_file;
+using abigail::abixml_reader::read_corpus_group_from_abixml_file;
 using abigail::comparison::corpus_diff_sptr;
 using abigail::comparison::translation_unit_diff_sptr;
 using abigail::comparison::compute_diff;
@@ -211,18 +211,18 @@ main(int, char*[])
 	  continue;
 	}
 
-      environment_sptr env(new environment);
+      environment env;
       translation_unit_sptr tu1, tu2;
       corpus_sptr corpus1, corpus2;
       corpus_group_sptr corpus_group1, corpus_group2;
       file_type t = guess_file_type(first_in_path);
       if (t == abigail::tools_utils::FILE_TYPE_NATIVE_BI)
-	tu1 = read_translation_unit_from_file(first_in_path, env.get());
+	tu1 = read_translation_unit_from_file(first_in_path, env);
       else if (t == abigail::tools_utils::FILE_TYPE_XML_CORPUS)
-	corpus1 = read_corpus_from_native_xml_file(first_in_path, env.get());
+	corpus1 = read_corpus_from_abixml_file(first_in_path, env);
       else if (t == abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP)
-	corpus_group1 = read_corpus_group_from_native_xml_file(first_in_path,
-							       env.get());
+	corpus_group1 = read_corpus_group_from_abixml_file(first_in_path,
+							   env);
       else
 	abort();
       if (!tu1 && !corpus1 && !corpus_group1)
@@ -234,12 +234,12 @@ main(int, char*[])
 
       t = guess_file_type(second_in_path);
       if (t == abigail::tools_utils::FILE_TYPE_NATIVE_BI)
-	tu2 = read_translation_unit_from_file(second_in_path, env.get());
+	tu2 = read_translation_unit_from_file(second_in_path, env);
       else if (t == abigail::tools_utils::FILE_TYPE_XML_CORPUS)
-	corpus2 = read_corpus_from_native_xml_file(second_in_path, env.get());
+	corpus2 = read_corpus_from_abixml_file(second_in_path, env);
       else if (t == abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP)
-	corpus_group2 = read_corpus_group_from_native_xml_file(first_in_path,
-							       env.get());
+	corpus_group2 = read_corpus_group_from_abixml_file(first_in_path,
+							   env);
       else
 	abort();
       if (!tu2 && !corpus2 && !corpus_group2)
diff --git a/tests/test-diff-dwarf.cc b/tests/test-diff-dwarf.cc
index 42e25dfa..0e00a3ce 100644
--- a/tests/test-diff-dwarf.cc
+++ b/tests/test-diff-dwarf.cc
@@ -380,24 +380,18 @@ main()
 	  continue;
 	}
 
-      abigail::elf_reader::status status =
-	abigail::elf_reader::STATUS_UNKNOWN;
+      abigail::fe_iface::status status =
+	abigail::fe_iface::STATUS_UNKNOWN;
 
-      environment_sptr env(new environment);
+      environment env;
       std::vector<char**> di_roots;
       abigail::corpus_sptr corp0 =
-	read_corpus_from_elf(in_elfv0_path,
-			     /*debug_info_root_path=*/di_roots,
-			     env.get(),
-			     /*load_all_types=*/false,
-			     status);
+	read_corpus_from_elf(in_elfv0_path, /*debug_info_root_path=*/di_roots,
+			     env, /*load_all_types=*/false, status);
 
       abigail::corpus_sptr corp1 =
-	read_corpus_from_elf(in_elfv1_path,
-			     /*debug_info_root_path=*/di_roots,
-			     env.get(),
-			     /*load_all_types=*/false,
-			     status);
+	read_corpus_from_elf(in_elfv1_path, /*debug_info_root_path=*/di_roots,
+			     env, /*load_all_types=*/false, status);
 
       if (!corp0)
 	{
diff --git a/tests/test-ir-walker.cc b/tests/test-ir-walker.cc
index b6042d20..c76d04a6 100644
--- a/tests/test-ir-walker.cc
+++ b/tests/test-ir-walker.cc
@@ -155,12 +155,11 @@ main(int argc, char **argv)
 
   string file_name = argv[1];
 
-  abigail::ir::environment_sptr env(new abigail::ir::environment);
+  abigail::ir::environment env;
   abigail::corpus_sptr c;
-  abigail::elf_reader::status status = abigail::elf_reader::STATUS_OK;
+  abigail::fe_iface::status status = abigail::fe_iface::STATUS_OK;
   std::vector<char**> di_roots;
-  if (!(c = abigail::dwarf_reader::read_corpus_from_elf(file_name, di_roots,
-							env.get(),
+  if (!(c = abigail::dwarf_reader::read_corpus_from_elf(file_name, di_roots, env,
 							/*load_all_type=*/false,
 							status)))
     {
diff --git a/tests/test-read-ctf.cc b/tests/test-read-ctf.cc
index b0ef7de6..3a7db586 100644
--- a/tests/test-read-ctf.cc
+++ b/tests/test-read-ctf.cc
@@ -29,8 +29,7 @@ using abigail::tests::read_common::test_task;
 using abigail::tests::read_common::display_usage;
 using abigail::tests::read_common::options;
 
-using abigail::ctf_reader::read_context_sptr;
-using abigail::ctf_reader::create_read_context;
+using abigail::ctf_reader::create_ctf_reader;
 using abigail::xml_writer::SEQUENCE_TYPE_ID_STYLE;
 using abigail::xml_writer::HASH_TYPE_ID_STYLE;
 using abigail::tools_utils::emit_prefix;
@@ -348,23 +347,22 @@ test_task_ctf::test_task_ctf(const InOutSpec &s,
 void
 test_task_ctf::perform()
 {
-  abigail::ir::environment_sptr env;
+  abigail::ir::environment env;
 
   set_in_elf_path();
   set_in_suppr_spec_path();
 
-  env.reset(new abigail::ir::environment);
-  abigail::elf_reader::status status =
-    abigail::elf_reader::STATUS_UNKNOWN;
+  abigail::fe_iface::status status =
+    abigail::fe_iface::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);
+  abigail::elf_based_reader_sptr rdr = create_ctf_reader(in_elf_path,
+							 di_roots, env);
+  ABG_ASSERT(rdr);
+
+  corpus_sptr corp = rdr->read_corpus(status);
 
-  corpus_sptr corp = read_corpus(ctxt.get(), status);
   // if there is no output and no input, assume that we do not care about the
   // actual read result, just that it succeeded.
   if (!spec.in_abi_path && !spec.out_abi_path)
diff --git a/tests/test-read-dwarf.cc b/tests/test-read-dwarf.cc
index 0227c89b..22292029 100644
--- a/tests/test-read-dwarf.cc
+++ b/tests/test-read-dwarf.cc
@@ -29,9 +29,6 @@ using abigail::tests::read_common::options;
 using abigail::tests::get_build_dir;
 
 using abigail::dwarf_reader::read_corpus_from_elf;
-using abigail::dwarf_reader::read_context;
-using abigail::dwarf_reader::read_context_sptr;
-using abigail::dwarf_reader::create_read_context;
 using abigail::xml_writer::SEQUENCE_TYPE_ID_STYLE;
 using abigail::xml_writer::HASH_TYPE_ID_STYLE;
 using abigail::xml_writer::type_id_style_kind;
diff --git a/tests/test-read-write.cc b/tests/test-read-write.cc
index 7e8e3ecc..52ebc294 100644
--- a/tests/test-read-write.cc
+++ b/tests/test-read-write.cc
@@ -36,9 +36,6 @@ using abigail::ir::environment;
 using abigail::ir::environment_sptr;
 using abigail::translation_unit_sptr;
 using abigail::corpus_sptr;
-using abigail::xml_reader::read_translation_unit_from_file;
-using abigail::xml_reader::read_corpus_from_native_xml_file;
-using abigail::xml_writer::write_translation_unit;
 
 using abigail::workers::queue;
 using abigail::workers::task;
diff --git a/tests/test-symtab.cc b/tests/test-symtab.cc
index efef9a99..68c30692 100644
--- a/tests/test-symtab.cc
+++ b/tests/test-symtab.cc
@@ -24,9 +24,7 @@
 
 using namespace abigail;
 
-using dwarf_reader::create_read_context;
-using dwarf_reader::read_context_sptr;
-using dwarf_reader::read_corpus_from_elf;
+using dwarf_reader::create_dwarf_reader;
 using ir::environment;
 using ir::environment_sptr;
 using suppr::suppressions_type;
@@ -34,7 +32,7 @@ using suppr::suppressions_type;
 static const std::string test_data_dir =
     std::string(abigail::tests::get_src_dir()) + "/tests/data/test-symtab/";
 
-elf_reader::status
+fe_iface::status
 read_corpus(const std::string&		    path,
 	    corpus_sptr&		    result,
 	    const std::vector<std::string>& whitelist_paths =
@@ -42,12 +40,12 @@ read_corpus(const std::string&		    path,
 {
   const std::string& absolute_path = test_data_dir + path;
 
-  environment_sptr	    env(new environment);
+  environment env;
   const std::vector<char**> debug_info_root_paths;
-  read_context_sptr	    ctxt =
-      create_read_context(absolute_path, debug_info_root_paths, env.get(),
-			  /* load_all_type = */ true,
-			  /* linux_kernel_mode = */ true);
+  abigail::elf_based_reader_sptr rdr =
+    create_dwarf_reader(absolute_path, debug_info_root_paths,
+			env, /* load_all_type = */ true,
+			/* linux_kernel_mode = */ true);
 
   if (!whitelist_paths.empty())
     {
@@ -55,13 +53,13 @@ read_corpus(const std::string&		    path,
 	tools_utils::gen_suppr_spec_from_kernel_abi_whitelists(
 	  whitelist_paths);
       REQUIRE_FALSE(wl_suppr.empty());
-      dwarf_reader::add_read_context_suppressions(*ctxt, wl_suppr);
+      rdr->add_suppressions(wl_suppr);
     }
 
-  elf_reader::status status = elf_reader::STATUS_UNKNOWN;
-  result = read_corpus_from_elf(*ctxt, status);
+  fe_iface::status status = fe_iface::STATUS_UNKNOWN;
+  result = rdr->read_corpus(status);
 
-  REQUIRE(status != elf_reader::STATUS_UNKNOWN);
+  REQUIRE(status != fe_iface::STATUS_UNKNOWN);
   return status;
 }
 
@@ -69,22 +67,22 @@ TEST_CASE("Symtab::Empty", "[symtab, basic]")
 {
   const std::string	     binary = "basic/empty.so";
   corpus_sptr		     corpus_ptr;
-  const elf_reader::status status = read_corpus(binary, corpus_ptr);
+  const fe_iface::status status = read_corpus(binary, corpus_ptr);
   REQUIRE(!corpus_ptr);
 
-  REQUIRE((status & elf_reader::STATUS_NO_SYMBOLS_FOUND));
+  REQUIRE((status & fe_iface::STATUS_NO_SYMBOLS_FOUND));
 }
 
 TEST_CASE("Symtab::NoDebugInfo", "[symtab, basic]")
 {
   const std::string	     binary = "basic/no_debug_info.so";
   corpus_sptr		     corpus_ptr;
-  const elf_reader::status status = read_corpus(binary, corpus_ptr);
+  const fe_iface::status status = read_corpus(binary, corpus_ptr);
   REQUIRE(corpus_ptr);
 
   REQUIRE(status
-	  == (elf_reader::STATUS_OK
-	      | elf_reader::STATUS_DEBUG_INFO_NOT_FOUND));
+	  == (fe_iface::STATUS_OK
+	      | fe_iface::STATUS_DEBUG_INFO_NOT_FOUND));
 }
 
 // this value indicates in the following helper method, that we do not want to
@@ -102,11 +100,11 @@ assert_symbol_count(const std::string& path,
 			std::vector<std::string>())
 {
   corpus_sptr		     corpus_ptr;
-  const elf_reader::status status =
+  const fe_iface::status status =
     read_corpus(path, corpus_ptr, whitelist_paths);
   REQUIRE(corpus_ptr);
 
-  REQUIRE((status & elf_reader::STATUS_OK));
+  REQUIRE((status & fe_iface::STATUS_OK));
   const corpus& corpus = *corpus_ptr;
 
   size_t total_symbols = 0;
@@ -244,10 +242,10 @@ TEST_CASE("Symtab::SymtabWithWhitelist", "[symtab, whitelist]")
 	+ "basic/one_function_one_variable_irrelevant.whitelist");
 
       corpus_sptr		 corpus_ptr;
-      const elf_reader::status status =
+      const fe_iface::status status =
 	read_corpus(binary, corpus_ptr, whitelists);
       REQUIRE(!corpus_ptr);
-      REQUIRE((status & elf_reader::STATUS_NO_SYMBOLS_FOUND));
+      REQUIRE((status & fe_iface::STATUS_NO_SYMBOLS_FOUND));
     }
 
     GIVEN("we read the binary with only the function whitelisted")
diff --git a/tools/Makefile.am b/tools/Makefile.am
index f7592b60..abd09022 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -10,41 +10,36 @@ else
 endif
 
 noinst_PROGRAMS = abisym abinilint
+LDADD = $(abs_top_builddir)/src/libabigail.la
 
 abidiff_SOURCES = abidiff.cc
 abidiffdir = $(bindir)
-abidiff_LDADD = ../src/libabigail.la
 
 abilint_SOURCES = abilint.cc
 abilintdir = $(bindir)
-abilint_LDADD = ../src/libabigail.la
 
 abidw_SOURCES = abidw.cc
 abidwdir = $(bindir)
-abidw_LDADD = ../src/libabigail.la
 
 abisym_SOURCES = abisym.cc
 abisymdir = $(bindir)
-abisym_LDADD = ../src/libabigail.la
 
 abinilint_SOURCES = binilint.cc
 abinilintdir = $(bindir)
-abinilint_LDADD = $(abs_top_builddir)/src/libabigail.la
 
 abicompat_SOURCES = abicompat.cc
 abicompatdir = $(bindir)
-abicompat_LDADD = $(abs_top_builddir)/src/libabigail.la
 
 abipkgdiff_SOURCES = abipkgdiff.cc
 abipkgdiffdir = $(bindir)
 abipkgdiff_CPPFLAGS = $(FTS_CFLAGS)
-abipkgdiff_LDADD = $(abs_top_builddir)/src/libabigail.la $(FTS_LIBS)
-abipkgdiff_LDFLAGS = -pthread
+abipkgdiff_LDADD = $(FTS_LIBS)
+abipkgdiff_LDFLAGS = $(abs_top_builddir)/src/libabigail.la -pthread
 
 kmidiff_SOURCES = kmidiff.cc
 kmidiffdir = $(bindir)
 kmidiff_LDADD = $(abs_top_builddir)/src/libabigail.la
-kmidiff_LDFLAGS = -pthread
+kmidiff_LDFLAGS = $(abs_top_builddir)/src/libabigail.la -pthread
 
 AM_CXXFLAGS = \
 $(VISIBILITY_FLAGS) -I$(abs_top_srcdir)/include \
diff --git a/tools/abicompat.cc b/tools/abicompat.cc
index 0be49a86..b015a7f7 100644
--- a/tools/abicompat.cc
+++ b/tools/abicompat.cc
@@ -274,9 +274,6 @@ using abigail::ir::type_base_sptr;
 using abigail::ir::function_type_sptr;
 using abigail::ir::function_decl;
 using abigail::ir::var_decl;
-using abigail::elf_reader::status;
-using abigail::elf_reader::STATUS_ALT_DEBUG_INFO_NOT_FOUND;
-using abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
 using abigail::dwarf_reader::read_corpus_from_elf;
 using abigail::comparison::diff_context_sptr;
 using abigail::comparison::diff_context;
@@ -646,7 +643,7 @@ perform_compat_check_in_weak_mode(options& opts,
 ///
 /// @param opts the options passed from the user to the program.
 ///
-/// @param status the resulting elf_reader::status to send back to the
+/// @param status the resulting fe_iface::status to send back to the
 /// caller.
 ///
 /// @param di_roots the directories from where to look for debug info.
@@ -655,14 +652,16 @@ perform_compat_check_in_weak_mode(options& opts,
 ///
 /// @param path the path to the ABI corpus to read from.
 static corpus_sptr
-read_corpus(options opts, status &status,
-	    const vector<char**> di_roots,
-	    const environment_sptr &env,
-	    const string &path)
+read_corpus(options			opts,
+	    abigail::fe_iface::status&	status,
+	    const vector<char**>	di_roots,
+	    environment		&env,
+	    const string		&path)
 {
   corpus_sptr retval = NULL;
   abigail::tools_utils::file_type type =
     abigail::tools_utils::guess_file_type(path);
+  abigail::fe_iface_sptr rdr;
 
   switch (type)
     {
@@ -675,26 +674,23 @@ read_corpus(options opts, status &status,
 #ifdef WITH_CTF
 	if (opts.use_ctf)
 	  {
-	    abigail::ctf_reader::read_context_sptr r_ctxt
-	      = abigail::ctf_reader::create_read_context(path,
-							 env.get());
-	    ABG_ASSERT(r_ctxt);
+	    rdr = abigail::ctf_reader::create_reader(path, env);
+	    ABG_ASSERT(rdr);
 
-	    retval = abigail::ctf_reader::read_corpus(r_ctxt.get(), status);
+	    retval = abigail::ctf_reader::read_corpus(rdr.get(), status);
 	  }
 	else
 #endif
-	  retval = read_corpus_from_elf(path, di_roots, env.get(),
+	  retval = read_corpus_from_elf(path, di_roots, env,
 					/*load_all_types=*/opts.weak_mode,
 					status);
       }
       break;
     case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
       {
-	abigail::xml_reader::read_context_sptr r_ctxt =
-	  abigail::xml_reader::create_native_xml_read_context(path, env.get());
-	assert(r_ctxt);
-	retval = abigail::xml_reader::read_corpus_from_input(*r_ctxt);
+	rdr = abigail::abixml_reader::create_abixml_reader(path, env);
+	assert(rdr);
+	retval = rdr->read_corpus(status);
       }
       break;
     case abigail::tools_utils::FILE_TYPE_AR:
@@ -788,8 +784,8 @@ main(int argc, char* argv[])
   char * app_di_root = opts.app_di_root_path.get();
   vector<char**> app_di_roots;
   app_di_roots.push_back(&app_di_root);
-  status status = abigail::elf_reader::STATUS_UNKNOWN;
-  environment_sptr env(new environment);
+  abigail::fe_iface::status status = abigail::fe_iface::STATUS_UNKNOWN;
+  environment env;
 
   corpus_sptr app_corpus = read_corpus(opts, status,
 				       app_di_roots, env,
@@ -801,20 +797,21 @@ main(int argc, char* argv[])
       return abigail::tools_utils::ABIDIFF_ERROR;
     }
 
-  if (opts.fail_no_debug_info && (status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
-      && (status & STATUS_DEBUG_INFO_NOT_FOUND))
+  if (opts.fail_no_debug_info
+      && (status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
+      && (status & abigail::fe_iface::STATUS_DEBUG_INFO_NOT_FOUND))
     {
       emit_prefix(argv[0], cerr) << opts.app_path
 				 << " does not have debug symbols\n";
       return abigail::tools_utils::ABIDIFF_ERROR;
     }
-  if (status & abigail::elf_reader::STATUS_NO_SYMBOLS_FOUND)
+  if (status & abigail::fe_iface::STATUS_NO_SYMBOLS_FOUND)
     {
       emit_prefix(argv[0], cerr)
 	<< "could not read symbols from " << opts.app_path << "\n";
       return abigail::tools_utils::ABIDIFF_ERROR;
     }
-  if (!(status & abigail::elf_reader::STATUS_OK))
+  if (!(status & abigail::fe_iface::STATUS_OK))
     {
       emit_prefix(argv[0], cerr)
 	<< "could not read file " << opts.app_path << "\n";
@@ -856,17 +853,18 @@ main(int argc, char* argv[])
 				 << " is not a supported file\n";
       return abigail::tools_utils::ABIDIFF_ERROR;
     }
-  if (opts.fail_no_debug_info && (status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
-      && (status & STATUS_DEBUG_INFO_NOT_FOUND))
+  if (opts.fail_no_debug_info
+      && (status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
+      && (status & abigail::fe_iface::STATUS_DEBUG_INFO_NOT_FOUND))
     emit_prefix(argv[0], cerr)
       << "could not read debug info for " << opts.lib1_path << "\n";
-  if (status & abigail::elf_reader::STATUS_NO_SYMBOLS_FOUND)
+  if (status & abigail::fe_iface::STATUS_NO_SYMBOLS_FOUND)
     {
       emit_prefix(argv[0], cerr) << "could not read symbols from "
 				 << opts.lib1_path << "\n";
       return abigail::tools_utils::ABIDIFF_ERROR;
     }
-  if (!(status & abigail::elf_reader::STATUS_OK))
+  if (!(status & abigail::fe_iface::STATUS_OK))
     {
       emit_prefix(argv[0], cerr)
 	<< "could not read file " << opts.lib1_path << "\n";
@@ -891,20 +889,21 @@ main(int argc, char* argv[])
 	  return abigail::tools_utils::ABIDIFF_ERROR;
 	}
 
-      if (opts.fail_no_debug_info && (status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
-	  && (status & STATUS_DEBUG_INFO_NOT_FOUND))
+      if (opts.fail_no_debug_info
+	  && (status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
+	  && (status & abigail::fe_iface::STATUS_DEBUG_INFO_NOT_FOUND))
 	{
 	  emit_prefix(argv[0], cerr)
 	    << "could not read debug info for " << opts.lib2_path << "\n";
 	  return abigail::tools_utils::ABIDIFF_ERROR;
 	}
-      if (status & abigail::elf_reader::STATUS_NO_SYMBOLS_FOUND)
+      if (status & abigail::fe_iface::STATUS_NO_SYMBOLS_FOUND)
 	{
 	  emit_prefix(argv[0], cerr)
 	    << "could not read symbols from " << opts.lib2_path << "\n";
 	  return abigail::tools_utils::ABIDIFF_ERROR;
 	}
-      if (!(status & abigail::elf_reader::STATUS_OK))
+      if (!(status & abigail::fe_iface::STATUS_OK))
 	{
 	  emit_prefix(argv[0], cerr)
 	    << "could not read file " << opts.lib2_path << "\n";
diff --git a/tools/abidiff.cc b/tools/abidiff.cc
index 9b2ab784..b35d4587 100644
--- a/tools/abidiff.cc
+++ b/tools/abidiff.cc
@@ -809,13 +809,12 @@ set_diff_context_from_opts(diff_context_sptr ctxt,
 /// specifications to.  Note that the type of this parameter is
 /// generic (class template) because in practise, it can be either an
 /// abigail::dwarf_reader::read_context type or an
-/// abigail::xml_reader::read_context type.
+/// abigail::abiabixml_reader::reader type.
 ///
 /// @param opts the options where to get the suppression
 /// specifications from.
-template<class ReadContextType>
 static void
-set_suppressions(ReadContextType& read_ctxt, const options& opts)
+set_suppressions(abigail::fe_iface& reader, const options& opts)
 {
   suppressions_type supprs;
   for (vector<string>::const_iterator i = opts.suppression_paths.begin();
@@ -823,7 +822,7 @@ set_suppressions(ReadContextType& read_ctxt, const options& opts)
        ++i)
     read_suppressions(*i, supprs);
 
-  if (read_context_get_path(read_ctxt) == opts.file1
+  if (reader.corpus_path() == opts.file1
       && (!opts.headers_dirs1.empty() || !opts.header_files1.empty()))
     {
       // Generate suppression specification to avoid showing ABI
@@ -843,7 +842,7 @@ set_suppressions(ReadContextType& read_ctxt, const options& opts)
 	}
     }
 
-  if (read_context_get_path(read_ctxt) == opts.file2
+  if (reader.corpus_path() == opts.file2
       && (!opts.headers_dirs2.empty() || !opts.header_files2.empty()))
     {
       // Generate suppression specification to avoid showing ABI
@@ -869,7 +868,7 @@ set_suppressions(ReadContextType& read_ctxt, const options& opts)
 
   supprs.insert(supprs.end(), wl_suppr.begin(), wl_suppr.end());
 
-  add_read_context_suppressions(read_ctxt, supprs);
+  reader.add_suppressions(supprs);
 }
 
 /// Configure the abigail::xml_reacher::read_context based on the
@@ -879,11 +878,11 @@ set_suppressions(ReadContextType& read_ctxt, const options& opts)
 ///
 /// @param opts the command-line options to configure @p ctxt from.
 static void
-set_native_xml_reader_options(abigail::xml_reader::read_context& ctxt,
+set_native_xml_reader_options(abigail::fe_iface& rdr,
 			      const options& opts)
 {
-  consider_types_not_reachable_from_public_interfaces(ctxt,
-						      opts.show_all_types);
+  abigail::abixml_reader::consider_types_not_reachable_from_public_interfaces(rdr,
+									      opts.show_all_types);
 }
 
 /// Set the regex patterns describing the functions to drop from the
@@ -979,17 +978,17 @@ prepare_di_root_paths(options& o)
 /// @return abigail::tools_utils::ABIDIFF_ERROR if an error was
 /// detected, abigail::tools_utils::ABIDIFF_OK otherwise.
 static abigail::tools_utils::abidiff_status
-handle_error(abigail::elf_reader::status status_code,
-	     const abigail::dwarf_reader::read_context* ctxt,
+handle_error(abigail::fe_iface::status status_code,
+	     const abigail::elf_based_reader* rdr,
 	     const string& prog_name,
 	     const options& opts)
 {
-  if (!(status_code & abigail::elf_reader::STATUS_OK))
+  if (!(status_code & abigail::fe_iface::STATUS_OK))
     {
       emit_prefix(prog_name, cerr)
 	<< "failed to read input file " << opts.file1 << "\n";
 
-      if (status_code & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
+      if (status_code & abigail::fe_iface::STATUS_DEBUG_INFO_NOT_FOUND)
 	{
 	  emit_prefix(prog_name, cerr) <<
 	    "could not find the debug info\n";
@@ -1042,22 +1041,18 @@ handle_error(abigail::elf_reader::status status_code,
 	  }
 	}
 
-      if (status_code & abigail::elf_reader::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
+      if (status_code & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
 	{
 	  emit_prefix(prog_name, cerr)
 	    << "could not find the alternate debug info file";
-	  if (ctxt)
-	    {
-	      string alt_di_path;
-	      abigail::dwarf_reader::refers_to_alt_debug_info(*ctxt,
-							      alt_di_path);
-	      if (!alt_di_path.empty())
-		cerr << " at: " << alt_di_path;
-	    }
-	  cerr << "\n";
+
+	   if (rdr->alternate_dwarf_debug_info())
+	    cerr << " at: "
+		 << rdr->alternate_dwarf_debug_info_path()
+		 << "\n";
 	}
 
-      if (status_code & abigail::elf_reader::STATUS_NO_SYMBOLS_FOUND)
+      if (status_code & abigail::fe_iface::STATUS_NO_SYMBOLS_FOUND)
 	emit_prefix(prog_name, cerr)
 	  << "could not find the ELF symbols in the file '"
 	  << opts.file1
@@ -1153,22 +1148,22 @@ main(int argc, char* argv[])
       t1_type = guess_file_type(opts.file1);
       t2_type = guess_file_type(opts.file2);
 
-      environment_sptr env(new environment);
+      environment env;
       if (opts.exported_interfaces_only.has_value())
-	env->analyze_exported_interfaces_only(*opts.exported_interfaces_only);
+	env.analyze_exported_interfaces_only(*opts.exported_interfaces_only);
 
 #ifdef WITH_DEBUG_SELF_COMPARISON
 	    if (opts.do_debug_self_comparison)
-	      env->self_comparison_debug_is_on(true);
+	      env.self_comparison_debug_is_on(true);
 #endif
 #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
 	    if (opts.do_debug_type_canonicalization)
-	      env->debug_type_canonicalization_is_on(true);
+	      env.debug_type_canonicalization_is_on(true);
 #endif
       translation_unit_sptr t1, t2;
-      abigail::elf_reader::status c1_status =
-	abigail::elf_reader::STATUS_OK,
-	c2_status = abigail::elf_reader::STATUS_OK;
+      abigail::fe_iface::status c1_status =
+	abigail::fe_iface::STATUS_OK,
+	c2_status = abigail::fe_iface::STATUS_OK;
       corpus_sptr c1, c2;
       corpus_group_sptr g1, g2;
       bool files_suppressed = false;
@@ -1193,69 +1188,62 @@ main(int argc, char* argv[])
 	  return abigail::tools_utils::ABIDIFF_ERROR;
 	  break;
 	case abigail::tools_utils::FILE_TYPE_NATIVE_BI:
-	  t1 = abigail::xml_reader::read_translation_unit_from_file(opts.file1,
-								    env.get());
+	  t1 = abigail::abixml_reader::read_translation_unit_from_file(opts.file1,
+								       env);
 	  break;
 	case abigail::tools_utils::FILE_TYPE_ELF: // fall through
 	case abigail::tools_utils::FILE_TYPE_AR:
 	  {
+	    abigail::elf_based_reader_sptr rdr;
 #ifdef WITH_CTF
             if (opts.use_ctf)
-              {
-                abigail::ctf_reader::read_context_sptr ctxt
-                  = abigail::ctf_reader::create_read_context(opts.file1,
-                                                             opts.prepared_di_root_paths1,
-                                                             env.get());
-                ABG_ASSERT(ctxt);
-                c1 = abigail::ctf_reader::read_corpus(ctxt.get(),
-                                                      c1_status);
-              }
+	      rdr = abigail::ctf_reader::create_ctf_reader(opts.file1,
+							   opts.prepared_di_root_paths1,
+							   env);
             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);
-              }
+	      rdr = abigail::dwarf_reader::create_dwarf_reader
+		(opts.file1, opts.prepared_di_root_paths1,
+		 env, /*read_all_types=*/opts.show_all_types,
+		 opts.linux_kernel_mode);
+
+	    assert(rdr);
+
+	    rdr->options().show_stats = opts.show_stats;
+	    rdr->options().do_log = opts.do_log;
+	    set_suppressions(*rdr, opts);
+	    c1 = rdr->read_corpus(c1_status);
+
+	    if (!c1
+		|| (opts.fail_no_debug_info
+		    && (c1_status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
+		    && (c1_status & abigail::fe_iface::STATUS_DEBUG_INFO_NOT_FOUND)))
+	      return handle_error(c1_status, rdr.get(),
+				  argv[0], opts);
+
 	  }
 	  break;
 	case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
 	  {
-	    abigail::xml_reader::read_context_sptr ctxt =
-	      abigail::xml_reader::create_native_xml_read_context(opts.file1,
-								  env.get());
-	    assert(ctxt);
-	    set_suppressions(*ctxt, opts);
-	    set_native_xml_reader_options(*ctxt, opts);
-	    c1 = abigail::xml_reader::read_corpus_from_input(*ctxt);
+	    abigail::fe_iface_sptr rdr =
+	      abigail::abixml_reader::create_abixml_reader(opts.file1, env);
+	    assert(rdr);
+	    set_suppressions(*rdr, opts);
+	    set_native_xml_reader_options(*rdr, opts);
+	    c1 = rdr->read_corpus(c1_status);
 	    if (!c1)
-	      return handle_error(c1_status, /*ctxt=*/0,
-				  argv[0], opts);
+	      return handle_error(c1_status, /*ctxt=*/0, argv[0], opts);
 	  }
 	  break;
 	case abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP:
 	  {
-	    abigail::xml_reader::read_context_sptr ctxt =
-	      abigail::xml_reader::create_native_xml_read_context(opts.file1,
-								  env.get());
-	    assert(ctxt);
-	    set_suppressions(*ctxt, opts);
-	    set_native_xml_reader_options(*ctxt, opts);
-	    g1 = abigail::xml_reader::read_corpus_group_from_input(*ctxt);
+	    abigail::fe_iface_sptr rdr =
+	      abigail::abixml_reader::create_abixml_reader(opts.file1,
+							   env);
+	    assert(rdr);
+	    set_suppressions(*rdr, opts);
+	    set_native_xml_reader_options(*rdr, opts);
+	    g1 = abigail::abixml_reader::read_corpus_group_from_input(*rdr);
 	    if (!g1)
 	      return handle_error(c1_status, /*ctxt=*/0,
 				  argv[0], opts);
@@ -1277,54 +1265,48 @@ main(int argc, char* argv[])
 	  return abigail::tools_utils::ABIDIFF_ERROR;
 	  break;
 	case abigail::tools_utils::FILE_TYPE_NATIVE_BI:
-	  t2 = abigail::xml_reader::read_translation_unit_from_file(opts.file2,
-								    env.get());
+	  t2 = abigail::abixml_reader::read_translation_unit_from_file(opts.file2,
+								       env);
 	  break;
 	case abigail::tools_utils::FILE_TYPE_ELF: // Fall through
 	case abigail::tools_utils::FILE_TYPE_AR:
 	  {
+	    abigail::elf_based_reader_sptr rdr;
 #ifdef WITH_CTF
             if (opts.use_ctf)
-              {
-                abigail::ctf_reader::read_context_sptr ctxt
-                  = abigail::ctf_reader::create_read_context(opts.file2,
-                                                             opts.prepared_di_root_paths2,
-                                                             env.get());
-                ABG_ASSERT(ctxt);
-                c2 = abigail::ctf_reader::read_corpus(ctxt.get(),
-                                                      c2_status);
-              }
+	      rdr = abigail::ctf_reader::create_ctf_reader(opts.file2,
+							   opts.prepared_di_root_paths2,
+							   env);
             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);
-              }
+	      rdr = abigail::dwarf_reader::create_dwarf_reader
+		(opts.file2, opts.prepared_di_root_paths2,
+		 env, /*read_all_types=*/opts.show_all_types,
+		 opts.linux_kernel_mode);
+
+	    assert(rdr);
+	    rdr->options().show_stats = opts.show_stats;
+	    rdr->options().do_log = opts.do_log;
+	    set_suppressions(*rdr, opts);
+
+	    c2 = rdr->read_corpus(c2_status);
+
+	    if (!c2
+		|| (opts.fail_no_debug_info
+		    && (c2_status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
+		    && (c2_status & abigail::fe_iface::STATUS_DEBUG_INFO_NOT_FOUND)))
+	      return handle_error(c2_status, rdr.get(), argv[0], opts);
 	  }
 	  break;
 	case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
 	  {
-	    abigail::xml_reader::read_context_sptr ctxt =
-	      abigail::xml_reader::create_native_xml_read_context(opts.file2,
-								  env.get());
-	    assert(ctxt);
-	    set_suppressions(*ctxt, opts);
-	    set_native_xml_reader_options(*ctxt, opts);
-	    c2 = abigail::xml_reader::read_corpus_from_input(*ctxt);
+	    abigail::fe_iface_sptr rdr =
+	      abigail::abixml_reader::create_abixml_reader(opts.file2,
+							   env);
+	    assert(rdr);
+	    set_suppressions(*rdr, opts);
+	    set_native_xml_reader_options(*rdr, opts);
+	    c2 = rdr->read_corpus(c2_status);
 	    if (!c2)
 	      return handle_error(c2_status, /*ctxt=*/0, argv[0], opts);
 
@@ -1332,13 +1314,13 @@ main(int argc, char* argv[])
 	  break;
 	case abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP:
 	  {
-	    abigail::xml_reader::read_context_sptr ctxt =
-	      abigail::xml_reader::create_native_xml_read_context(opts.file2,
-								  env.get());
-	    assert(ctxt);
-	    set_suppressions(*ctxt, opts);
-	    set_native_xml_reader_options(*ctxt, opts);
-	    g2 = abigail::xml_reader::read_corpus_group_from_input(*ctxt);
+	    abigail::fe_iface_sptr rdr =
+	      abigail::abixml_reader::create_abixml_reader(opts.file2,
+							   env);
+	    assert(rdr);
+	    set_suppressions(*rdr, opts);
+	    set_native_xml_reader_options(*rdr, opts);
+	    g2 = abigail::abixml_reader::read_corpus_group_from_input(*rdr);
 	    if (!g2)
 	      return handle_error(c2_status, /*ctxt=*/0, argv[0], opts);
 	  }
diff --git a/tools/abidw.cc b/tools/abidw.cc
index f38d6048..d92ec198 100644
--- a/tools/abidw.cc
+++ b/tools/abidw.cc
@@ -32,6 +32,7 @@
 #include "abg-writer.h"
 #include "abg-reader.h"
 #include "abg-comparison.h"
+#include "abg-suppression.h"
 
 using std::string;
 using std::cerr;
@@ -66,8 +67,9 @@ using abigail::xml_writer::create_write_context;
 using abigail::xml_writer::type_id_style_kind;
 using abigail::xml_writer::write_context_sptr;
 using abigail::xml_writer::write_corpus;
-using abigail::xml_reader::read_corpus_from_native_xml_file;
-using abigail::xml_reader::create_native_xml_read_context;
+using abigail::abixml_reader::read_corpus_from_abixml_file;
+using abigail::abixml_reader::create_abixml_reader;
+
 using namespace abigail;
 
 struct options
@@ -489,7 +491,7 @@ maybe_check_header_files(const options& opts)
 /// @param opts the options where to get the suppression
 /// specifications from.
 static void
-set_suppressions(dwarf_reader::read_context& read_ctxt, options& opts)
+set_suppressions(abigail::elf_based_reader& rdr, options& opts)
 {
   suppressions_type supprs;
   for (vector<string>::const_iterator i = opts.suppression_paths.begin();
@@ -514,8 +516,8 @@ set_suppressions(dwarf_reader::read_context& read_ctxt, options& opts)
   opts.kabi_whitelist_supprs.insert(opts.kabi_whitelist_supprs.end(),
 				    wl_suppr.begin(), wl_suppr.end());
 
-  add_read_context_suppressions(read_ctxt, supprs);
-  add_read_context_suppressions(read_ctxt, opts.kabi_whitelist_supprs);
+  rdr.add_suppressions(supprs);
+  rdr.add_suppressions(opts.kabi_whitelist_supprs);
 }
 
 /// Load an ABI @ref corpus (the internal representation of the ABI of
@@ -531,7 +533,7 @@ set_suppressions(dwarf_reader::read_context& read_ctxt, options& opts)
 /// otherwise.
 static int
 load_corpus_and_write_abixml(char* argv[],
-			     environment_sptr& env,
+			     environment& env,
 			     options& opts)
 {
   int exit_code = 0;
@@ -539,106 +541,92 @@ load_corpus_and_write_abixml(char* argv[],
 
 #ifdef WITH_DEBUG_SELF_COMPARISON
   if (opts.debug_abidiff)
-    env->self_comparison_debug_is_on(true);
+    env.self_comparison_debug_is_on(true);
 #endif
 
 #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
   if (opts.debug_type_canonicalization)
-    env->debug_type_canonicalization_is_on(true);
+    env.debug_type_canonicalization_is_on(true);
   if (opts.debug_die_canonicalization)
-    env->debug_die_canonicalization_is_on(true);
+    env.debug_die_canonicalization_is_on(true);
 #endif
 
-  // First of all, read a libabigail IR corpus from the file specified
-  // in OPTS.
   corpus_sptr corp;
-  elf_reader::status s = elf_reader::STATUS_UNKNOWN;
+  fe_iface::status s = fe_iface::STATUS_UNKNOWN;
+  // First of all, create a reader to read the ABI from the file
+  // specfied in opts ...
+  abigail::elf_based_reader_sptr reader;
 #ifdef WITH_CTF
   if (opts.use_ctf)
-    {
-      abigail::ctf_reader::read_context_sptr ctxt
-        = abigail::ctf_reader::create_read_context(opts.in_file_path,
-                                                   opts.prepared_di_root_paths,
-                                                   env.get());
-      assert (ctxt);
-      t.start();
-      corp = abigail::ctf_reader::read_corpus (ctxt, s);
-      t.stop();
-      if (opts.do_log)
-        emit_prefix(argv[0], cerr)
-          << "read corpus from elf file in: " << t << "\n";
-    }
+    reader = abigail::ctf_reader::create_ctf_reader(opts.in_file_path,
+						    opts.prepared_di_root_paths,
+						    env);
   else
 #endif
+    reader = abigail::dwarf_reader::create_dwarf_reader(opts.in_file_path,
+							opts.prepared_di_root_paths,
+							env,
+							opts.load_all_types,
+							opts.linux_kernel_mode);
+
+  // ... then tune a bunch of "buttons" on the newly created reader ...
+  reader->options().drop_undefined_syms = opts.drop_undefined_syms;
+  reader->options().show_stats = opts.show_stats;
+  reader->options().do_log = opts.do_log;
+  set_suppressions(*reader, opts);
+
+  // If the user asked us to check if we found the "alternate debug
+  // info file" associated to the input binary, then proceed to do so
+  // ...
+  if (opts.check_alt_debug_info_path)
     {
-      dwarf_reader::read_context_sptr c
-        = abigail::dwarf_reader::create_read_context(opts.in_file_path,
-                                                     opts.prepared_di_root_paths,
-                                                     env.get(),
-                                                     opts.load_all_types,
-                                                     opts.linux_kernel_mode);
-      dwarf_reader::read_context& ctxt = *c;
-      set_drop_undefined_syms(ctxt, opts.drop_undefined_syms);
-      set_show_stats(ctxt, opts.show_stats);
-      set_suppressions(ctxt, opts);
-      abigail::dwarf_reader::set_do_log(ctxt, opts.do_log);
-
-      if (opts.check_alt_debug_info_path)
-        {
-          bool has_alt_di = false;
-          string alt_di_path;
-          abigail::elf_reader::status status =
-            abigail::dwarf_reader::has_alt_debug_info(ctxt,
-                                                      has_alt_di,
-                                                      alt_di_path);
-          if (status & abigail::elf_reader::STATUS_OK)
-            {
-              if (alt_di_path.empty())
-                ;
-              else
-                {
-                  cout << "found the alternate debug info file";
-                  if (opts.show_base_name_alt_debug_info_path)
-                    {
-                      tools_utils::base_name(alt_di_path, alt_di_path);
-                      cout << " '" << alt_di_path << "'";
-                    }
-                  cout << "\n";
-                }
-              return 0;
-            }
-          else
-            {
-              emit_prefix(argv[0], cerr)
-                << "could not find alternate debug info file\n";
-              return 1;
-            }
-        }
+      string alt_di_path = reader->alternate_dwarf_debug_info_path();
+      if (!alt_di_path.empty())
+	{
+	  cout << "found the alternate debug info file";
+	  if (opts.show_base_name_alt_debug_info_path)
+	    {
+	      tools_utils::base_name(alt_di_path, alt_di_path);
+	      cout << " '" << alt_di_path << "'";
+	    }
+	  cout << "\n";
+	  return 0;
+	}
+      else
+	{
+	  emit_prefix(argv[0], cerr)
+	    << "could not find alternate debug info file\n";
+	  return 1;
+	}
+    }
 
-      if (opts.exported_interfaces_only.has_value())
-	env->analyze_exported_interfaces_only(*opts.exported_interfaces_only);
+  // ... ff we are asked to only analyze exported interfaces (to stay
+  // concise), then take that into account ...
+  if (opts.exported_interfaces_only.has_value())
+    env.analyze_exported_interfaces_only(*opts.exported_interfaces_only);
 
-      t.start();
-      corp = dwarf_reader::read_corpus_from_elf(ctxt, s);
-      t.stop();
-      if (opts.do_log)
-        emit_prefix(argv[0], cerr)
-          << "read corpus from elf file in: " << t << "\n";
+  // And now, really read/analyze the ABI of the input file.
+  t.start();
+  corp = reader->read_corpus(s);
+  t.stop();
+  if (opts.do_log)
+    emit_prefix(argv[0], cerr)
+      << "read corpus from elf file in: " << t << "\n";
 
-      t.start();
-      c.reset();
-      t.stop();
+  // Clear some resources to gain back some space.
+  t.start();
+  reader.reset();
+  t.stop();
 
-      if (opts.do_log)
-        emit_prefix(argv[0], cerr)
-          << "reset read context in: " << t << "\n";
-    }
+  if (opts.do_log)
+    emit_prefix(argv[0], cerr)
+      << "reset reader ELF in: " << t << "\n";
 
   // If we couldn't create a corpus, emit some (hopefully) useful
   // diagnostics and return and error.
   if (!corp)
     {
-      if (s == elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
+      if (s == fe_iface::STATUS_DEBUG_INFO_NOT_FOUND)
 	{
 	  if (opts.di_root_paths.empty())
 	    {
@@ -668,7 +656,7 @@ load_corpus_and_write_abixml(char* argv[],
 		}
 	    }
 	}
-      else if (s == elf_reader::STATUS_NO_SYMBOLS_FOUND)
+      else if (s == fe_iface::STATUS_NO_SYMBOLS_FOUND)
 	emit_prefix(argv[0], cerr)
 	  << "Could not read ELF symbol information from "
 	  << opts.in_file_path << "\n";
@@ -679,8 +667,7 @@ load_corpus_and_write_abixml(char* argv[],
   // Now create a write context and write out an ABI XML description
   // of the read corpus.
   t.start();
-  const write_context_sptr& write_ctxt
-    = create_write_context(corp->get_environment(), cout);
+  const write_context_sptr& write_ctxt = create_write_context(env, cout);
   set_common_options(*write_ctxt, opts);
   t.stop();
 
@@ -706,17 +693,16 @@ load_corpus_and_write_abixml(char* argv[],
           write_canonical_type_ids(*write_ctxt, opts.type_id_file_path);
         }
 #endif
-      xml_reader::read_context_sptr read_ctxt =
-        create_native_xml_read_context(tmp_file->get_path(), env.get());
+      fe_iface_sptr rdr = create_abixml_reader(tmp_file->get_path(), env);
 
 #ifdef WITH_DEBUG_SELF_COMPARISON
       if (opts.debug_abidiff
           && !opts.type_id_file_path.empty())
-        load_canonical_type_ids(*read_ctxt, opts.type_id_file_path);
+        load_canonical_type_ids(*rdr, opts.type_id_file_path);
 #endif
       t.start();
-      corpus_sptr corp2 =
-        read_corpus_from_input(*read_ctxt);
+      fe_iface::status sts;
+      corpus_sptr corp2 = rdr->read_corpus(sts);
       t.stop();
       if (opts.do_log)
         emit_prefix(argv[0], cerr)
@@ -810,7 +796,7 @@ load_corpus_and_write_abixml(char* argv[],
 /// otherwise.
 static int
 load_kernel_corpus_group_and_write_abixml(char* argv[],
-					  environment_sptr& env,
+					  environment& env,
 					  options& opts)
 {
   if (!(tools_utils::is_dir(opts.in_file_path) && opts.corpus_group_for_linux))
@@ -826,7 +812,7 @@ load_kernel_corpus_group_and_write_abixml(char* argv[],
   suppressions_type supprs;
 
   if (opts.exported_interfaces_only.has_value())
-    env->analyze_exported_interfaces_only(*opts.exported_interfaces_only);
+    env.analyze_exported_interfaces_only(*opts.exported_interfaces_only);
 
   if (opts.do_log)
     emit_prefix(argv[0], cerr)
@@ -861,7 +847,7 @@ corpus::origin origin =
   if (!opts.noout)
     {
       const xml_writer::write_context_sptr& ctxt
-	  = xml_writer::create_write_context(group->get_environment(), cout);
+	  = xml_writer::create_write_context(env, cout);
       set_common_options(*ctxt, opts);
 
       if (!opts.out_file_path.empty())
@@ -983,7 +969,7 @@ main(int argc, char* argv[])
       return 1;
     }
 
-  environment_sptr env(new environment);
+  environment env;
   int exit_code = 0;
 
   if (tools_utils::is_regular_file(opts.in_file_path))
diff --git a/tools/abilint.cc b/tools/abilint.cc
index 087fc45f..d2664c09 100644
--- a/tools/abilint.cc
+++ b/tools/abilint.cc
@@ -56,14 +56,14 @@ using abigail::type_base_sptr;
 using abigail::type_or_decl_base_sptr;
 using abigail::corpus;
 using abigail::corpus_sptr;
-using abigail::xml_reader::read_translation_unit_from_file;
-using abigail::xml_reader::read_translation_unit_from_istream;
-using abigail::xml_reader::read_corpus_from_native_xml;
-using abigail::xml_reader::read_corpus_from_native_xml_file;
-using abigail::xml_reader::read_corpus_group_from_input;
+using abigail::abixml_reader::read_translation_unit_from_file;
+using abigail::abixml_reader::read_translation_unit_from_istream;
+using abigail::abixml_reader::read_corpus_from_abixml;
+using abigail::abixml_reader::read_corpus_from_abixml_file;
+using abigail::abixml_reader::read_corpus_group_from_input;
 #ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
-using abigail::xml_reader::get_types_from_type_id;
-using abigail::xml_reader::get_artifact_used_by_relation_map;
+using abigail::abixml_reader::get_types_from_type_id;
+using abigail::abixml_reader::get_artifact_used_by_relation_map;
 #endif
 using abigail::dwarf_reader::read_corpus_from_elf;
 using abigail::xml_writer::write_translation_unit;
@@ -302,7 +302,7 @@ fill_artifact_use_tree(const std::unordered_map<type_or_decl_base*,
 /// @param type_id the type-id of the type to construct the "use tree"
 /// for.
 static unique_ptr<artifact_use_relation_tree>
-build_type_use_tree(abigail::xml_reader::read_context &ctxt,
+build_type_use_tree(abigail::abixml_reader::reader &ctxt,
 		    const string& type_id)
 {
   unique_ptr<artifact_use_relation_tree> result;
@@ -452,7 +452,7 @@ emit_artifact_use_trace(const artifact_use_relation_tree& artifact_use_tree,
 ///
 /// @param the type_id of the type which usage to analyse.
 static bool
-show_how_type_is_used(abigail::xml_reader::read_context &ctxt,
+show_how_type_is_used(abigail::abixml_reader::reader &ctxt,
 		      const string& type_id)
 {
   if (type_id.empty())
@@ -641,7 +641,7 @@ maybe_check_suppression_files(const options& opts)
   return true;
 }
 
-/// Set suppression specifications to the @p read_context used to load
+/// Set suppression specifications to the @p reader used to load
 /// the ABI corpus from the ELF/DWARF file.
 ///
 /// These suppression specifications are going to be applied to drop
@@ -652,14 +652,13 @@ maybe_check_suppression_files(const options& opts)
 /// @param read_ctxt the read context to apply the suppression
 /// specifications to.  Note that the type of this parameter is
 /// generic (class template) because in practise, it can be either an
-/// abigail::dwarf_reader::read_context type or an
-/// abigail::xml_reader::read_context type.
+/// abigail::dwarf_reader::reader type or an
+/// abigail::abixml_reader::reader type.
 ///
 /// @param opts the options where to get the suppression
 /// specifications from.
-template<class ReadContextType>
 static void
-set_suppressions(ReadContextType& read_ctxt, const options& opts)
+set_suppressions(abigail::fe_iface& reader, const options& opts)
 {
   suppressions_type supprs;
   for (vector<string>::const_iterator i = opts.suppression_paths.begin();
@@ -673,7 +672,7 @@ set_suppressions(ReadContextType& read_ctxt, const options& opts)
   if (suppr)
     supprs.push_back(suppr);
 
-  add_read_context_suppressions(read_ctxt, supprs);
+  reader.add_suppressions(supprs);
 }
 
 /// Reads a bi (binary instrumentation) file, saves it back to a
@@ -702,7 +701,7 @@ main(int argc, char* argv[])
   if (!maybe_check_suppression_files(opts))
     return 1;
 
-  abigail::ir::environment_sptr env(new abigail::ir::environment);
+  abigail::ir::environment env;
   if (opts.read_from_stdin)
     {
       if (!cin.good())
@@ -711,7 +710,7 @@ main(int argc, char* argv[])
       if (opts.read_tu)
 	{
 	  abigail::translation_unit_sptr tu =
-	    read_translation_unit_from_istream(&cin, env.get());
+	    read_translation_unit_from_istream(&cin, env);
 
 	  if (!tu)
 	    {
@@ -723,23 +722,23 @@ main(int argc, char* argv[])
 	  if (!opts.noout)
 	    {
 	      const write_context_sptr& ctxt
-		  = create_write_context(tu->get_environment(), cout);
+		  = create_write_context(env, cout);
 	      write_translation_unit(*ctxt, *tu, 0);
 	    }
 	  return 0;
 	}
       else
 	{
-	  abigail::xml_reader::read_context_sptr ctxt =
-	    abigail::xml_reader::create_native_xml_read_context(&cin,
-								env.get());
-	  assert(ctxt);
-	  set_suppressions(*ctxt, opts);
-	  corpus_sptr corp = abigail::xml_reader::read_corpus_from_input(*ctxt);
+	  abigail::fe_iface_sptr rdr =
+	    abigail::abixml_reader::create_abixml_reader(&cin, env);
+	  assert(rdr);
+	  set_suppressions(*rdr, opts);
+	  abigail::fe_iface::status sts;
+	  corpus_sptr corp = rdr->read_corpus(sts);
 	  if (!opts.noout)
 	    {
 	      const write_context_sptr& ctxt
-		  = create_write_context(corp->get_environment(), cout);
+		  = create_write_context(env, cout);
 	      write_corpus(*ctxt, corp, /*indent=*/0);
 	    }
 	  return 0;
@@ -752,10 +751,9 @@ main(int argc, char* argv[])
       abigail::translation_unit_sptr tu;
       abigail::corpus_sptr corp;
       abigail::corpus_group_sptr group;
-      abigail::elf_reader::status s = abigail::elf_reader::STATUS_OK;
+      abigail::fe_iface::status s = abigail::fe_iface::STATUS_OK;
       char* di_root_path = 0;
       file_type type = guess_file_type(opts.file_path);
-      abigail::xml_reader::read_context_sptr abixml_read_ctxt;
 
       switch (type)
 	{
@@ -766,10 +764,10 @@ main(int argc, char* argv[])
 	  return 1;
 	case abigail::tools_utils::FILE_TYPE_NATIVE_BI:
 	  {
-	    abixml_read_ctxt =
-	      abigail::xml_reader::create_native_xml_read_context(opts.file_path,
-								  env.get());
-	    tu = read_translation_unit(*abixml_read_ctxt);
+	    abigail::fe_iface_sptr rdr =
+	      abigail::abixml_reader::create_abixml_reader(opts.file_path,
+							   env);
+	    tu = abigail::abixml_reader::read_translation_unit(*rdr);
 	  }
 	  break;
 	case abigail::tools_utils::FILE_TYPE_ELF:
@@ -778,48 +776,41 @@ 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::elf_based_reader_sptr rdr;
 #ifdef WITH_CTF
             if (opts.use_ctf)
-              {
-                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);
-              }
+	      rdr =
+		abigail::ctf_reader::create_ctf_reader(opts.file_path,
+						       di_roots,
+						       env);
             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);
-              }
+	      rdr =
+		abigail::dwarf_reader::create_dwarf_reader(opts.file_path,
+							   di_roots, env,
+							   /*load_all_types=*/false);
+	    set_suppressions(*rdr, opts);
+	    corp = rdr->read_corpus(s);
 	  }
 	  break;
 	case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
 	  {
-	    abixml_read_ctxt =
-	      abigail::xml_reader::create_native_xml_read_context(opts.file_path,
-								  env.get());
-	    assert(abixml_read_ctxt);
-	    set_suppressions(*abixml_read_ctxt, opts);
-	    corp = read_corpus_from_input(*abixml_read_ctxt);
+	    abigail::fe_iface_sptr rdr =
+	      abigail::abixml_reader::create_abixml_reader(opts.file_path,
+							   env);
+	    assert(rdr);
+	    set_suppressions(*rdr, opts);
+	    corp = rdr->read_corpus(s);
 	    break;
 	  }
 	case abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP:
 	  {
-	    abixml_read_ctxt =
-	      abigail::xml_reader::create_native_xml_read_context(opts.file_path,
-								  env.get());
-	    assert(abixml_read_ctxt);
-	    set_suppressions(*abixml_read_ctxt, opts);
-	    group = read_corpus_group_from_input(*abixml_read_ctxt);
+	    abigail::fe_iface_sptr rdr =
+	      abigail::abixml_reader::create_abixml_reader(opts.file_path,
+							   env);
+	    assert(rdr);
+	    set_suppressions(*rdr, opts);
+	    group = read_corpus_group_from_input(*rdr);
 	  }
 	  break;
 	case abigail::tools_utils::FILE_TYPE_RPM:
@@ -838,9 +829,9 @@ main(int argc, char* argv[])
 	{
 	  emit_prefix(argv[0], cerr)
 	    << "failed to read " << opts.file_path << "\n";
-	  if (!(s & abigail::elf_reader::STATUS_OK))
+	  if (!(s & abigail::fe_iface::STATUS_OK))
 	    {
-	      if (s & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
+	      if (s & abigail::fe_iface::STATUS_DEBUG_INFO_NOT_FOUND)
 		{
 		  cerr << "could not find the debug info";
 		  if(di_root_path == 0)
@@ -854,7 +845,7 @@ main(int argc, char* argv[])
 		      << "Maybe the root path to the debug "
 		      "information is wrong?\n";
 		}
-	      if (s & abigail::elf_reader::STATUS_NO_SYMBOLS_FOUND)
+	      if (s & abigail::fe_iface::STATUS_NO_SYMBOLS_FOUND)
 		emit_prefix(argv[0], cerr)
 		  << "could not find the ELF symbols in the file "
 		  << opts.file_path
@@ -874,15 +865,6 @@ main(int argc, char* argv[])
 	}
 
       std::ostream& of = opts.diff ? tmp_file->get_stream() : cout;
-      const abigail::ir::environment* env = 0;
-      if (tu)
-	env = tu->get_environment();
-      else if (corp)
-	env = corp->get_environment();
-      else if (group)
-	env = group->get_environment();
-
-      ABG_ASSERT(env);
       const write_context_sptr ctxt = create_write_context(env, of);
 
       bool is_ok = true;
diff --git a/tools/abipkgdiff.cc b/tools/abipkgdiff.cc
index 656d5882..0065e763 100644
--- a/tools/abipkgdiff.cc
+++ b/tools/abipkgdiff.cc
@@ -147,11 +147,9 @@ using abigail::comparison::get_default_harmful_categories_bitmap;
 using abigail::suppr::suppression_sptr;
 using abigail::suppr::suppressions_type;
 using abigail::suppr::read_suppressions;
-using abigail::dwarf_reader::read_context_sptr;
-using abigail::dwarf_reader::create_read_context;
-using abigail::dwarf_reader::get_soname_of_elf_file;
-using abigail::dwarf_reader::get_type_of_elf_file;
-using abigail::dwarf_reader::read_corpus_from_elf;
+using abigail::elf_reader::get_soname_of_elf_file;
+using abigail::elf_reader::get_type_of_elf_file;
+using abigail::dwarf_reader::create_dwarf_reader;
 using abigail::xml_writer::create_write_context;
 using abigail::xml_writer::write_context_sptr;
 using abigail::xml_writer::write_corpus;
@@ -279,7 +277,7 @@ public:
   string				name;
   string				soname;
   off_t				size;
-  abigail::dwarf_reader::elf_type	type;
+  abigail::elf_reader::elf_type	type;
 
   /// The path to the elf file.
   ///
@@ -1248,22 +1246,22 @@ set_diff_context_from_opts(diff_context_sptr ctxt,
 ///
 /// @param detailed_error_status is this pointer is non-null and if
 /// the function returns ABIDIFF_ERROR, then the function sets the
-/// pointed-to parameter to the abigail::elf_reader::status value
+/// pointed-to parameter to the abigail::fe_iface::status value
 /// that gives details about the rror.
 ///
 /// @return the status of the comparison.
 static abidiff_status
-compare(const elf_file& elf1,
-	const string&	debug_dir1,
-	const suppressions_type& priv_types_supprs1,
-	const elf_file& elf2,
-	const string&	debug_dir2,
-	const suppressions_type& priv_types_supprs2,
-	const options&	opts,
-	abigail::ir::environment_sptr	&env,
-	corpus_diff_sptr	&diff,
-	diff_context_sptr	&ctxt,
-	abigail::elf_reader::status *detailed_error_status = 0)
+compare(const elf_file&		elf1,
+	const string&			debug_dir1,
+	const suppressions_type&	priv_types_supprs1,
+	const elf_file&		elf2,
+	const string&			debug_dir2,
+	const suppressions_type&	priv_types_supprs2,
+	const options&			opts,
+	abigail::ir::environment&	env,
+	corpus_diff_sptr&		diff,
+	diff_context_sptr&		ctxt,
+	abigail::fe_iface::status*	detailed_error_status = 0)
 {
   char *di_dir1 = (char*) debug_dir1.c_str(),
 	*di_dir2 = (char*) debug_dir2.c_str();
@@ -1280,8 +1278,8 @@ compare(const elf_file& elf1,
       << elf2.path
       << "...\n";
 
-  abigail::elf_reader::status c1_status = abigail::elf_reader::STATUS_OK,
-    c2_status = abigail::elf_reader::STATUS_OK;
+  abigail::fe_iface::status c1_status = abigail::fe_iface::STATUS_OK,
+    c2_status = abigail::fe_iface::STATUS_OK;
 
   ctxt.reset(new diff_context);
   set_diff_context_from_opts(ctxt, opts);
@@ -1320,36 +1318,28 @@ compare(const elf_file& elf1,
       << elf1.path
       << " ...\n";
 
+  abigail::elf_based_reader_sptr reader;
   corpus_sptr corpus1;
-#ifdef WITH_CTF
-  abigail::ctf_reader::read_context_sptr ctxt_ctf;
-#endif
-  read_context_sptr ctxt_dwarf;
   {
 #ifdef WITH_CTF
     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(),
-                                                   c1_status);
-      }
+      reader = abigail::ctf_reader::create_ctf_reader(elf1.path, di_dirs1, env);
     else
 #endif
-      {
-        ctxt_dwarf = create_read_context(elf1.path, di_dirs1, env.get(),
-                                         /*load_all_types=*/opts.show_all_types);
-        add_read_context_suppressions(*ctxt_dwarf, priv_types_supprs1);
-        if (!opts.kabi_suppressions.empty())
-          add_read_context_suppressions(*ctxt_dwarf, opts.kabi_suppressions);
+      reader =
+	create_dwarf_reader(elf1.path, di_dirs1, env,
+			    /*load_all_types=*/opts.show_all_types);
 
-        corpus1 = read_corpus_from_elf(*ctxt_dwarf, c1_status);
-      }
+    ABG_ASSERT(reader);
+
+    reader->add_suppressions(priv_types_supprs1);
+    if (!opts.kabi_suppressions.empty())
+      reader->add_suppressions(opts.kabi_suppressions);
+
+    corpus1 = reader->read_corpus(c1_status);
 
     bool bail_out = false;
-    if (!(c1_status & abigail::elf_reader::STATUS_OK))
+    if (!(c1_status & abigail::fe_iface::STATUS_OK))
       {
 	if (opts.verbose)
 	  emit_prefix("abipkgdiff", cerr)
@@ -1366,7 +1356,7 @@ compare(const elf_file& elf1,
     if (opts.fail_if_no_debug_info)
       {
 	bool debug_info_error = false;
-	if (c1_status & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
+	if (c1_status & abigail::fe_iface::STATUS_DEBUG_INFO_NOT_FOUND)
 	  {
 	    if (opts.verbose)
 	      emit_prefix("abipkgdiff", cerr)
@@ -1383,7 +1373,7 @@ compare(const elf_file& elf1,
 	    debug_info_error = true;
 	  }
 
-	if (c1_status & abigail::elf_reader::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
+	if (c1_status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
 	  {
 	    if (opts.verbose)
 	      emit_prefix("abipkgdiff", cerr)
@@ -1397,8 +1387,7 @@ compare(const elf_file& elf1,
               ;
             else
 #endif
-              abigail::dwarf_reader::refers_to_alt_debug_info(*ctxt_dwarf,
-                                                              alt_di_path);
+	      reader->refers_to_alt_debug_info(alt_di_path);
 	    if (!alt_di_path.empty())
 	      cerr << ": " << alt_di_path << "\n";
 	    else
@@ -1433,28 +1422,22 @@ compare(const elf_file& elf1,
   {
 #ifdef WITH_CTF
     if (opts.use_ctf)
-      {
-        ctxt_ctf = abigail::ctf_reader::create_read_context(elf2.path,
-							    di_dirs2,
-							    env.get());
-        corpus2 = abigail::ctf_reader::read_corpus(ctxt_ctf.get(),
-                                                   c2_status);
-      }
+      reader =
+	abigail::ctf_reader::create_ctf_reader(elf2.path, di_dirs2, env);
     else
 #endif
-      {
-        ctxt_dwarf = create_read_context(elf2.path, di_dirs2, env.get(),
-                                         /*load_all_types=*/opts.show_all_types);
-        add_read_context_suppressions(*ctxt_dwarf, priv_types_supprs2);
+      reader =
+	create_dwarf_reader(elf2.path, di_dirs2, env,
+			      /*load_all_types=*/opts.show_all_types);
 
-        if (!opts.kabi_suppressions.empty())
-          add_read_context_suppressions(*ctxt_dwarf, opts.kabi_suppressions);
+    reader->add_suppressions(priv_types_supprs2);
+    if (!opts.kabi_suppressions.empty())
+      reader->add_suppressions(opts.kabi_suppressions);
 
-        corpus2 = read_corpus_from_elf(*ctxt_dwarf, c2_status);
-      }
+    corpus2 = reader->read_corpus(c2_status);
 
     bool bail_out = false;
-    if (!(c2_status & abigail::elf_reader::STATUS_OK))
+    if (!(c2_status & abigail::fe_iface::STATUS_OK))
       {
 	if (opts.verbose)
 	  emit_prefix("abipkgdiff", cerr)
@@ -1471,7 +1454,7 @@ compare(const elf_file& elf1,
     if (opts.fail_if_no_debug_info)
       {
 	bool debug_info_error = false;
-	if (c2_status & abigail::elf_reader::STATUS_DEBUG_INFO_NOT_FOUND)
+	if (c2_status & abigail::fe_iface::STATUS_DEBUG_INFO_NOT_FOUND)
 	  {
 	    if (opts.verbose)
 	      emit_prefix("abipkgdiff", cerr)
@@ -1488,7 +1471,7 @@ compare(const elf_file& elf1,
 	    debug_info_error = true;
 	  }
 
-	if (c2_status & abigail::elf_reader::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
+	if (c2_status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
 	  {
 	    if (opts.verbose)
 	      emit_prefix("abipkgdiff", cerr)
@@ -1502,8 +1485,7 @@ compare(const elf_file& elf1,
               ;
             else
 #endif
-              abigail::dwarf_reader::refers_to_alt_debug_info(*ctxt_dwarf,
-                                                              alt_di_path);
+	      reader->refers_to_alt_debug_info(alt_di_path);
 	    if (!alt_di_path.empty())
 	      cerr << ": " << alt_di_path << "\n";
 	    else
@@ -1572,20 +1554,20 @@ compare(const elf_file& elf1,
 ///
 /// @return the status of the self comparison.
 static abidiff_status
-compare_to_self(const elf_file& elf,
-		const string&	debug_dir,
-		const options&	opts,
-		abigail::ir::environment_sptr	&env,
-		corpus_diff_sptr	&diff,
-		diff_context_sptr	&ctxt,
-		abigail::elf_reader::status *detailed_error_status = 0)
+compare_to_self(const elf_file&		elf,
+		const string&			debug_dir,
+		const options&			opts,
+		abigail::ir::environment&	env,
+		corpus_diff_sptr&		diff,
+		diff_context_sptr&		ctxt,
+		abigail::fe_iface::status*	detailed_error_status = 0)
 {
   char *di_dir = (char*) debug_dir.c_str();
 
   vector<char**> di_dirs;
   di_dirs.push_back(&di_dir);
 
-  abigail::elf_reader::status c_status = abigail::elf_reader::STATUS_OK;
+  abigail::fe_iface::status c_status = abigail::fe_iface::STATUS_OK;
 
   if (opts.verbose)
     emit_prefix("abipkgdiff", cerr)
@@ -1600,32 +1582,20 @@ compare_to_self(const elf_file& elf,
       << " ...\n";
 
   corpus_sptr corp;
-#ifdef WITH_CTF
-  abigail::ctf_reader::read_context_sptr ctxt_ctf;
-#endif
-  read_context_sptr ctxt_dwarf;
+  abigail::elf_based_reader_sptr reader;
   {
 #ifdef WITH_CTF
     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(),
-                                                   c_status);
-      }
+      reader =
+	  abigail::ctf_reader::create_ctf_reader(elf.path, di_dirs, env);
     else
 #endif
-      {
-        ctxt_dwarf =
-         create_read_context(elf.path, di_dirs, env.get(),
-                             /*read_all_types=*/opts.show_all_types);
+      reader = create_dwarf_reader(elf.path, di_dirs, env,
+				   /*read_all_types=*/opts.show_all_types);
 
-        corp = read_corpus_from_elf(*ctxt_dwarf, c_status);
-      }
+    corp = reader->read_corpus(c_status);
 
-    if (!(c_status & abigail::elf_reader::STATUS_OK))
+    if (!(c_status & abigail::fe_iface::STATUS_OK))
       {
 	if (opts.verbose)
 	  emit_prefix("abipkgdiff", cerr)
@@ -1666,7 +1636,7 @@ compare_to_self(const elf_file& elf,
 
     {
       const abigail::xml_writer::write_context_sptr c =
-	abigail::xml_writer::create_write_context(env.get(), of);
+	abigail::xml_writer::create_write_context(env, of);
 
       if (opts.verbose)
 	emit_prefix("abipkgdiff", cerr)
@@ -1695,10 +1665,9 @@ compare_to_self(const elf_file& elf,
     }
 
     {
-      abigail::xml_reader::read_context_sptr c =
-	abigail::xml_reader::create_native_xml_read_context(abi_file_path,
-							    env.get());
-      if (!c)
+      abigail::fe_iface_sptr rdr =
+	abigail::abixml_reader::create_abixml_reader(abi_file_path, env);
+      if (!rdr)
 	{
 	  if (opts.verbose)
 	    emit_prefix("abipkgdiff", cerr)
@@ -1714,7 +1683,8 @@ compare_to_self(const elf_file& elf,
 	  << abi_file_path
 	  << "' ...\n";
 
-      reread_corp = read_corpus_from_input(*c);
+      abigail::fe_iface::status sts;
+      reread_corp = rdr->read_corpus(sts);
       if (!reread_corp)
 	{
 	  if (opts.verbose)
@@ -2074,15 +2044,15 @@ public:
   virtual void
   perform()
   {
-    abigail::ir::environment_sptr env(new abigail::ir::environment);
+    abigail::ir::environment env;
     diff_context_sptr ctxt;
     corpus_diff_sptr diff;
 
-    abigail::elf_reader::status detailed_status =
-      abigail::elf_reader::STATUS_UNKNOWN;
+    abigail::fe_iface::status detailed_status =
+      abigail::fe_iface::STATUS_UNKNOWN;
 
     if (args->opts.exported_interfaces_only.has_value())
-      env->analyze_exported_interfaces_only
+      env.analyze_exported_interfaces_only
 	(*args->opts.exported_interfaces_only);
 
     status |= compare(args->elf1, args->debug_dir1, args->private_types_suppr1,
@@ -2113,7 +2083,7 @@ public:
     if (status & abigail::tools_utils::ABIDIFF_ERROR)
       {
 	string diagnostic =
-	  abigail::elf_reader::status_to_diagnostic_string(detailed_status);
+	  abigail::status_to_diagnostic_string(detailed_status);
 	if (diagnostic.empty())
 	  diagnostic =
 	    "Unknown error.  Please run the tool again with --verbose\n";
@@ -2147,16 +2117,16 @@ public:
   virtual void
   perform()
   {
-    abigail::ir::environment_sptr env(new abigail::ir::environment);
+    abigail::ir::environment env;
     diff_context_sptr ctxt;
     corpus_diff_sptr diff;
 
     if (args->opts.exported_interfaces_only.has_value())
-      env->analyze_exported_interfaces_only
+      env.analyze_exported_interfaces_only
 	(*args->opts.exported_interfaces_only);
 
-    abigail::elf_reader::status detailed_status =
-      abigail::elf_reader::STATUS_UNKNOWN;
+    abigail::fe_iface::status detailed_status =
+      abigail::fe_iface::STATUS_UNKNOWN;
 
     status |= compare_to_self(args->elf1, args->debug_dir1,
 			      args->opts, env, diff, ctxt,
@@ -2183,7 +2153,7 @@ public:
     if (status & abigail::tools_utils::ABIDIFF_ERROR)
       {
 	string diagnostic =
-	  abigail::elf_reader::status_to_diagnostic_string(detailed_status);
+	  abigail::status_to_diagnostic_string(detailed_status);
 
 	if (diagnostic.empty())
 	  diagnostic =
@@ -2370,7 +2340,7 @@ create_maps_of_package_content(package& package, options& opts)
       elf_file_sptr e (new elf_file(*file));
       if (opts.compare_dso_only)
 	{
-	  if (e->type != abigail::dwarf_reader::ELF_TYPE_DSO)
+	  if (e->type != abigail::elf_reader::ELF_TYPE_DSO)
 	    {
 	      if (opts.verbose)
 		emit_prefix("abipkgdiff", cerr)
@@ -2380,13 +2350,13 @@ create_maps_of_package_content(package& package, options& opts)
 	}
       else
 	{
-	  if (e->type != abigail::dwarf_reader::ELF_TYPE_DSO
-	      && e->type != abigail::dwarf_reader::ELF_TYPE_EXEC
-              && e->type != abigail::dwarf_reader::ELF_TYPE_PI_EXEC)
+	  if (e->type != abigail::elf_reader::ELF_TYPE_DSO
+	      && e->type != abigail::elf_reader::ELF_TYPE_EXEC
+              && e->type != abigail::elf_reader::ELF_TYPE_PI_EXEC)
 	    {
 	      if (is_linux_kernel_package)
 		{
-		  if (e->type == abigail::dwarf_reader::ELF_TYPE_RELOCATABLE)
+		  if (e->type == abigail::elf_reader::ELF_TYPE_RELOCATABLE)
 		    {
 		      // This is a Linux Kernel module.
 		      ;
@@ -2405,7 +2375,7 @@ create_maps_of_package_content(package& package, options& opts)
 
       if (e->soname.empty())
 	{
-	  if (e->type == abigail::dwarf_reader::ELF_TYPE_DSO
+	  if (e->type == abigail::elf_reader::ELF_TYPE_DSO
 	      && must_compare_public_dso_only(package, opts))
 	    {
 	      // We are instructed to compare public DSOs only.  Yet
@@ -2751,12 +2721,12 @@ compare_prepared_userspace_packages(package& first_package,
 	second_package.path_elf_file_sptr_map().find(it->first);
 
       if (iter != second_package.path_elf_file_sptr_map().end()
-	  && (iter->second->type == abigail::dwarf_reader::ELF_TYPE_DSO
-	      || iter->second->type == abigail::dwarf_reader::ELF_TYPE_EXEC
-              || iter->second->type == abigail::dwarf_reader::ELF_TYPE_PI_EXEC
-	      || iter->second->type == abigail::dwarf_reader::ELF_TYPE_RELOCATABLE))
+	  && (iter->second->type == abigail::elf_reader::ELF_TYPE_DSO
+	      || iter->second->type == abigail::elf_reader::ELF_TYPE_EXEC
+              || iter->second->type == abigail::elf_reader::ELF_TYPE_PI_EXEC
+	      || iter->second->type == abigail::elf_reader::ELF_TYPE_RELOCATABLE))
 	{
-	  if (iter->second->type != abigail::dwarf_reader::ELF_TYPE_RELOCATABLE)
+	  if (iter->second->type != abigail::elf_reader::ELF_TYPE_RELOCATABLE)
 	    {
 	      if (opts.verbose)
 		emit_prefix("abipkgdiff", cerr)
@@ -2914,12 +2884,12 @@ self_compare_prepared_userspace_package(package&	pkg,
        ++it)
     {
       if (it != pkg.path_elf_file_sptr_map().end()
-	  && (it->second->type == abigail::dwarf_reader::ELF_TYPE_DSO
-	      || it->second->type == abigail::dwarf_reader::ELF_TYPE_EXEC
-              || it->second->type == abigail::dwarf_reader::ELF_TYPE_PI_EXEC
-	      || it->second->type == abigail::dwarf_reader::ELF_TYPE_RELOCATABLE))
+	  && (it->second->type == abigail::elf_reader::ELF_TYPE_DSO
+	      || it->second->type == abigail::elf_reader::ELF_TYPE_EXEC
+              || it->second->type == abigail::elf_reader::ELF_TYPE_PI_EXEC
+	      || it->second->type == abigail::elf_reader::ELF_TYPE_RELOCATABLE))
 	{
-	  if (it->second->type != abigail::dwarf_reader::ELF_TYPE_RELOCATABLE)
+	  if (it->second->type != abigail::elf_reader::ELF_TYPE_RELOCATABLE)
 	    {
 	      compare_args_sptr args
 		(new compare_args(*it->second,
@@ -3036,9 +3006,9 @@ compare_prepared_linux_kernel_packages(package& first_package,
   string dist_root1 = first_package.extracted_dir_path();
   string dist_root2 = second_package.extracted_dir_path();
 
-  abigail::ir::environment_sptr env(new abigail::ir::environment);
+  abigail::ir::environment env;
   if (opts.exported_interfaces_only.has_value())
-    env->analyze_exported_interfaces_only
+    env.analyze_exported_interfaces_only
       (*opts.exported_interfaces_only);
 
   suppressions_type supprs;
diff --git a/tools/abisym.cc b/tools/abisym.cc
index 1e2215a6..902a3f83 100644
--- a/tools/abisym.cc
+++ b/tools/abisym.cc
@@ -28,7 +28,6 @@ using std::ostringstream;
 using std::vector;
 
 using abigail::ir::environment;
-using abigail::ir::environment_sptr;
 using abigail::dwarf_reader::lookup_symbol_from_elf;
 using abigail::elf_symbol;
 using abigail::elf_symbol_sptr;
@@ -131,9 +130,9 @@ main(int argc, char* argv[])
 	 && opts.symbol_name != 0);
 
   string p = opts.elf_path, n = opts.symbol_name;
-  environment_sptr env(new environment);
+  environment env;
   vector<elf_symbol_sptr> syms;
-  if (!lookup_symbol_from_elf(env.get(), p, n, opts.demangle, syms))
+  if (!lookup_symbol_from_elf(env, p, n, opts.demangle, syms))
     {
       cout << "could not find symbol '"
 	   << opts.symbol_name
diff --git a/tools/kmidiff.cc b/tools/kmidiff.cc
index f3332765..699ab829 100644
--- a/tools/kmidiff.cc
+++ b/tools/kmidiff.cc
@@ -48,7 +48,7 @@ using abigail::suppr::suppressions_type;
 using abigail::suppr::read_suppressions;
 using abigail::tools_utils::guess_file_type;
 using abigail::tools_utils::file_type;
-using abigail::xml_reader::read_corpus_group_from_native_xml_file;
+using abigail::abixml_reader::read_corpus_group_from_abixml_file;
 
 /// The options of this program.
 struct options
@@ -415,10 +415,10 @@ main(int argc, char* argv[])
       return 0;
     }
 
-  environment_sptr env(new environment);
+  environment env;
 
   if (opts.exported_interfaces_only.has_value())
-    env->analyze_exported_interfaces_only(*opts.exported_interfaces_only);
+    env.analyze_exported_interfaces_only(*opts.exported_interfaces_only);
 
   corpus_group_sptr group1, group2;
   string debug_info_root_dir;
@@ -450,8 +450,8 @@ main(int argc, char* argv[])
 	}
       else if (ftype == FILE_TYPE_XML_CORPUS_GROUP)
 	group1 =
-	  read_corpus_group_from_native_xml_file(opts.kernel_dist_root1,
-						 env.get());
+	  read_corpus_group_from_abixml_file(opts.kernel_dist_root1,
+					     env);
 
     }
 
@@ -476,8 +476,8 @@ main(int argc, char* argv[])
 	}
       else if (ftype == FILE_TYPE_XML_CORPUS_GROUP)
 	group2 =
-	  read_corpus_group_from_native_xml_file(opts.kernel_dist_root2,
-						 env.get());
+	  read_corpus_group_from_abixml_file(opts.kernel_dist_root2,
+					     env);
     }
 
   abidiff_status status = abigail::tools_utils::ABIDIFF_OK;
