[2/2] Make Front Ends first class citizens

Message ID 878rkaolii.fsf@redhat.com
State New
Headers
Series Make front-ends be first class in the libabigail framework |

Commit Message

Dodji Seketeli Nov. 16, 2022, 5:29 p.m. UTC
  Hello,

This patch is a reorganization of the code to better support the need
for having several different front-ends.

In the libabigail pipeline of operation, a front-end is the part of
the pipeline that analyses the input file.  For instance, to analyse
an ELF file, there is going to be one front-end.  To analyse an ABIXML
file, there is going to be another front-end.

The middle-end is the part of the pipeline that interacts with the
internal representation of ABIs.  The middle-end knows how to analyse,
compare ABI corpora provide an internal representation of the
comparison result and analyse it as well.

The back-end would be the part of the front-end that knows how to
serialize internal representations of ABIs and ABI comparison results.

One could thus imagine a front-end that understands the DWARF debug
info format embedded in an ELF file.  Another front-end would be
dedicated to the CTF debug info format, and so on.

Front-ends can share capabilities.  For instance, DWARF and CTF
front-ends are ELF based front end.  As such, they share capabilities
to understand the ELF format.  They don't share much with the ABIXML
front-end, however, as it's based on XML, which has almost nothing in
common with ELF.

To support this organization of concepts, this patch introduces a new
hierarchy of types in the form of C++ classes.

All front-ends implements the "Front End Interface".  As such, they
all inherit the abigail::fe_iface class.

That class provides properties and behaviours that are shared by all
front-ends that libabigail supports today.  Namely, that class
provides access to some of the options that are relevant to operating
the front-end, to the ABI corpus or corpus group being constructed and
to the suppression specifications that are considered.  It also
provides an abstract interface to perform the actual loading of the
ABI corpus.  That abstract interface has to be implemented by every
single concrete front-end that is provided in libabigail.

Then, there is the "ELF Reader" front-end.  Its class name is
abigail::elf::reader.  It inherits the abigail::fe_iface class and
implements the fe_iface::load_corpus() so that the ELF properties of
the ELF file be loaded and exposed in the ABI corpus as returned by
the fe_iface::corpus() accessor.  This ELF reader front-end also
provides lots of capabilities that are specific to accessing ELF
content.

Then, there is a common base class for ELF-based front-ends to come,
named abigail::elf_based_reader, which inherits the abigail::elf::reader
class.  The purpose of this base class is to provide common properties
and behaviours that are necessary to implement things like a DWARF or
a CTF front-end, or any other front-end to support an ELF-based debug
info format.

Then, there is a CTF front-end which class is named
abigail::ctf::reader.  It inherits the abigail::elf_based_reader class
and implements the fe_iface::load_corpus() interface to load and
analyse the CTF-specific properties of the ELF file.  To do this,
abigail::ctf::reader::load_corpus() re-uses the abigail::elf::load_corpus() member
function to load the generic ELF parts of the ABI corpus.  This reader
then constructs the internal representation of the ABI corpus and
passes it to the middle-end for further analysis.

Then, there is a DWARF front-end which class is named
abigail::dwarf::reader.  It inherits the abigail::elf_based_reader
class and implements the fe_iface::load_corpus() interface to load and
analyse the DWARF-specific properties of the ELF file.  To do this,
abigail::dwarf::reader re-uses the abigail::elf::load_corpus() member
function to load the generic ELF parts of the ABI corpus, just like
what the CTF front-end does.  And then, just like the CTF front-end,
this reader then constructs the internal representation of the ABI
corpus and passes it to the middle-end for further analysis.

Lastly, there is an ABIXML front-end which class is named
abigail::abixml::reader.  It inherits the abigail::fe_iface class
directly.  Note that unlike the two previous front-ends, this one
doesn't inherit the elf_based_reader base class, for reasons that
should be obvious to the astute reader by now.  So, this front-end
implements the abigail::fe_iface::load_corpus() abstract interface to
load the properties for the ABI corpus represented in the ABIXML
format, construct the internal representation and pass it to the
middle-end for further analysis.

The code of the tools got adapted to use these front-ends.

The support of CTF is still guarded by #ifdef WITH_CTF pre-processor
macros, but the one cool side effect is that the amount of guarded
code is reduced.  Basically, it's only the creation of the CTF
front-end that is guarded.  After its creation, what is returned is an
instance of abigail::elf_based_reader::reader, exactly like what is
returned by the creation of a DWARF front-end.  Thus, the rest of the
code is exactly the same, regardless of the kind of front-end.  I
believe this results in a more elegant and maintainable code.

As a proof-of-concept, this patch also provides the
create_best_elf_based_reader function.  This function analyses the ELF
file and depending on the kind of debug info it provides, returns the
right front-end for it.  Maybe at some point, all the #ifdef WITH_CTF
guard pre-processing macros will be constrained in a single function
like this one that will take the decision of instantiating the right
front-end.  The rest of the code will be as generic as it gets.

The patch adjusts the reference abixml files produced by the CTF
front-end because it now emits the <elf-needed> XML element which was
not emitted before.  This is done because the CTF front-end inherits
the elf-reader which reads the "elf-needed" property from the binary,
without explicit intervention from the CTF front-end.

The patch passes 'make distcheck' on all the supported platforms.

	* include/abg-fwd.h (build_internal_underlying_enum_type_name):
	Move this here from src/abg-dwarf-reader.cc.
	* include/abg-elf-reader-common.h: Delete this file.  Its content
	is going to be put in the new include/abg-elf-reader.h.
	* src/abg-elf-reader-common.cc: Likewise.
	* include/abg-{elf-based-reader, elf-reader, fe-iface}.h: Add new
	files.
	* src/abg-fe-iface.cc: Likewise.
	* include/Makefile.am: Add the new file abg-fe-iface.h,
	abg-elf-based-reader.h and abg-elf-reader.h to source distribution
	and remove include/abg-elf-reader-common.h from source
	distribution.
	* src/abg-ir.cc (build_internal_underlying_enum_type_name): Move
	this here from abg-dwarf-reader.cc so that it can be used by other
	readers.
	* include/abg-reader.h (abigail::abixml::reader): Rename the
	namespace abigail::xml_reader into this one.
	(read_context, create_native_xml_read_context)
	(read_context_get_path, read_corpus_from_native_xml)
	(read_corpus_from_native_xml_file)
	(read_corpus_group_from_native_xml)
	(read_corpus_group_from_native_xml_file): Remove.
	(read_translation_unit_from_file)
	(read_translation_unit_from_buffer)
	(read_translation_unit_from_istream)
	(read_translation_unit)
	(consider_types_not_reachable_from_public_interfaces)
	(get_types_from_type_id, get_artifact_used_by_relation_map)
	(load_canonical_type_ids): Take an fe_iface&, not a read_context.
	(create_reader): Declare new function that returns a
	fe_iface_sptr.
	(read_corpus_from_abixml, read_corpus_from_abixml_file)
	(read_corpus_group_from_abixml)
	(read_corpus_group_from_abixml_file): Declare new functions.
	* src/abg-reader.cc (namespace abixml): Rename the
	xml_reader namespace into this.
	(abixml::reader_sptr): New typedef.
	(abixml::reader): Rename read_context into this.  Make it
	inherit the fe_iface interface.
	(abixml::reader::{m_path, m_env, m_corpus, m_corpus_group,
	m_exported_decls_builder, m_supprs}): Remove these data members
	that are now part of the fe_iface parent type.
	(abixml::reader::{set_environment, get_corpus, set_corpus,
	set_corpus_group, maybe_add_fn_to_exported_decls,
	maybe_add_var_to_exported_decls,
	maybe_check_abixml_canonical_type_stability,
	suppression_matches_function_sym_name,
	suppression_matches_variable_name,
	suppression_matches_variable_sym_name}): Remove.
	(read_corpus_from_input): Remove.  Actually the code of this went
	into abixml::reader::read_context().
	(abixml::reader::get_libxml_reader): Rename the get_reader
	member function into this.
	(abixml::add_reader_suppressions): Rename
	add_read_context_suppressions into this.
	(abixml::reader::read_corpus): Implement this virtual
	member function if the fe_iface parent interface.
	(maybe_set_naming_typedef, advance_cursor)
	(handle_version_attribute, walk_xml_node_to_map_type_ids)
	(read_elf_needed_from_input, read_symbol_db_from_input)
	(get_or_read_and_add_translation_unit, build_needed)
	(read_elf_needed_from_input, add_read_context_suppressions)
	(maybe_set_artificial_location, maybe_set_naming_typedef)
	(build_namespace_decl, build_elf_symbol)
	(build_elf_symbol_from_reference, build_elf_symbol_db)
	(build_function_parameter, build_function_decl)
	(build_function_decl_if_not_suppressed, function_is_suppressed)
	(type_is_suppressed, build_var_decl_if_not_suppressed)
	(variable_is_suppressed, variable_is_suppressed, build_var_decl)
	(build_type_decl, build_qualified_type_decl)
	(build_pointer_type_def, build_reference_type_def)
	(build_function_type, build_subrange_type, build_array_type_def)
	(build_enum_type_decl_if_not_suppressed, build_enum_type_decl)
	(build_typedef_decl, build_class_decl_if_not_suppressed)
	(build_union_decl_if_not_suppressed, build_class_decl)
	(build_union_decl, build_function_tdecl, build_class_tdecl)
	(build_type_tparameter, build_type_composition)
	(build_non_type_tparameter, build_non_type_tparameter)
	(build_template_tparameter, build_template_parameter, build_type)
	(handle_type_decl, handle_namespace_decl)
	(handle_qualified_type_decl, handle_pointer_type_def)
	(handle_reference_type_def, handle_function_type)
	(handle_array_type_def, handle_enum_type_decl)
	(handle_typedef_decl, handle_var_decl, handle_function_decl)
	(handle_class_decl, handle_union_decl, handle_function_tdecl)
	(read_translation_unit_from_istream): Take or use an
	abixml::reader rather than a read_context.
	(read_translation_unit, read_translation_unit_from_input)
	(consider_types_not_reachable_from_public_interfaces)
	(get_types_from_type_id, get_artifact_used_by_relation_map)
	(read_corpus_group_from_input, read_translation_unit)
	(handle_element_node, read_location, read_artificial_location)
	(load_canonical_type_ids) : Take an fe_iface&, not a read_context.
	(create_abixml_reader): Rename create_native_xml_read_context
	into this.  Make it return a fe_iface_sptr.
	(read_corpus_from_abixml): Rename read_corpus_from_abixml into
	this.
	(read_corpus_from_abixml_file): Rename
	read_corpus_from_native_xml_file into this.
	(read_context_get_path): Remove.
	* include/abg-tools-utils.h
	(abigail::tools_utils::{file_has_dwarf_debug_info,
	file_has_ctf_debug_info}): Declare new functions.
	(create_best_elf_based_reader): Declare new function.
	* include/abg-corpus.h (corpus::add): Pass the translation unit by
	reference.
	(corpus::exported_decls_builder::maybe_add_{fn,var}_to_exported_fns):
	Take a const parameter.
	* src/abg-corpus-priv.h
	(corpus::exported_decls_builder::priv::add_{fn,var}_to_exported):
	Take a const parameter and adjust.
	* src/abg-corpus.cc
	(corpus::exported_decls_builder::maybe_add_{fn,var}_to_exported_fns):
	Take a const parameter.
	(corpus::add): Take a reference to translation_unit_sptr.
	* include/abg-suppression.h (abigail::fe_iface): Forward-declare
	this.
	(abigail::{suppression_sptr, suppressions_type}): Declare these
	types here.
	(abigail::suppr::{suppression_can_match,
	suppression_matches_function_name,
	suppression_matches_function_sym_name,
	suppression_matches_variable_name,
	suppression_matches_variable_sym_name,
	suppression_matches_type_name_or_location,
	is_elf_symbol_suppressed, is_elf_symbol_suppressed,
	is_function_suppressed, is_variable_suppressed,
	is_type_suppressed}): Declare these functions here.
	* src/abg-suppression-priv.h (function_is_suppressed)
	(variable_is_suppressed, type_is_suppressed)
	(is_elf_symbol_suppressed): Remove these template functions.
	* src/abg-suppression.cc (suppression_matches_function_name)
	(suppression_matches_function_sym_name): Remove.
	(variable_is_suppressed, suppression_can_match)
	(suppression_matches_function_name)
	(suppression_matches_function_sym_name)
	(suppression_matches_variable_name)
	(suppression_matches_variable_sym_name)
	(suppression_matches_type_name_or_location)
	(is_elf_symbol_suppressed, is_elf_symbol_suppressed)
	(is_function_suppressed, is_variable_suppressed)
	(is_type_suppressed): New functions.
	* include/abg-ctf-reader.h (abigail::ctf::{read_context,
	create_read_context, read_corpus,
	read_and_add_corpus_to_group_from_elf,
	set_read_context_corpus_group, reset_read_context, dic_type_key}):
	Remove.
	(ctf::{create_reader, reset_reader}): Declare new
	functions.
	* src/abg-ctf-reader.cc (read_context): Remove.
	(process_ctf_typedef, process_ctf_base_type)
	(build_ir_node_for_variadic_parameter_type)
	(process_ctf_function_type, process_ctf_sou_members)
	(process_ctf_forward_type, process_ctf_struct_type)
	(process_ctf_union_type, process_ctf_array_type)
	(process_ctf_qualified_type, process_ctf_pointer_type)
	(process_ctf_enum_type, fill_ctf_section)
	(lookup_symbol_in_ctf_archive, dic_type_key): Forward-declare
	these static functions.
	(ctf::reader): New class that is the abstraction
	of the CTF reader.  It extends the abigail::elf_based_reader
	class.  This is a renaming of the
	abigail::ctf::read_context class.
	(ctf::reader::{elf_handler, elf_fd,
	elf_handler_dbg, elf_fd_dbg, symtab, debug_info_root_paths_,
	debug_info_root_paths_}): Remove these data members as they are
	now properties of the abigail::elf_reader class, which is a parent
	class of this abigail::ctf::reader class.
	(ctf::reader::{exported_decls_builder,
	maybe_add_fn_to_exported_decls, current_corpus_group,
	has_corpus_group, main_corpus_from_current_group,
	current_corpus_is_main_corpus_from_current_group,
	should_reuse_type_from_corpus_group}): Remove these accessors
	that can now be used from the parent classes abigail::{elf_reader,
	elf_based_reader}.
	(ctf::reader::reader): This now delegates to the constructor of
	elf_based_reader.  It doesn't pass any argument to initialize()
	anymore.
	(ctf::reader::initialize): Add an overload with no
	parameter.  In the other overload, do not take a pointer to an
	environment as no new environment can be passed to the instance of
	reader that is being reset.  Adjust the code of the initializer to
	reflect all the data members that got removed.
	(ctf::{env, find_ctfa_file, slurp_elf_info,
	process_ctf_archive, process_ctf_type, lookup_type, read_corpus,
	~reader}): New member functions.  Most of these were free-form
	functions that took ctf::read_context as first parameter.
	In read_corpus, do not set the corpus::LINUX_KERNEL_BINARY_ORIGIN
	origin as that is now done by elf::reader when it reads the
	binary.
	(lookup_type): Remove.  These are now member functions of the
	ctf::reader class.
	(process_ctf_typedef, process_ctf_base_type)
	(build_ir_node_for_variadic_parameter_type)
	(process_ctf_function_type, process_ctf_sou_members)
	(process_ctf_forward_type, process_ctf_struct_type)
	(process_ctf_union_type, process_ctf_array_type)
	(process_ctf_qualified_type, process_ctf_pointer_type): Take a
	ctf::reader rather an ctf::read_context.  Adjust the
	content of the functions.
	(process_ctf_type, lookup_type, process_ctf_archive): Remove these
	and turn them into member functions of ctf::reader.
	(open_elf_handler, close_elf_handler, find_alt_debuginfo): Remove
	these ELF handling functions as ELF handling is now done by the
	elf_reader parent class.
	(fill_ctf_section): Take a const pointer to Elf_Scn.
	(slurp_elf_info, find_ctfa_file): Remove this and make it be a
	member of ctf::reader.  Also, make it handle only CTF
	reader specific pieces.  slurp_elf_info now delegates the reading
	of generic ELF properties to elf::reader by calling
	elf::reader::read_corpus().
	(create_read_context, read_corpus, set_read_context_corpus_group)
	(read_and_add_corpus_to_group_from_elf): Remove these functions.
	(create_reader, reset_reader): Create new functions
	(dic_type_key): Make this static.
	* include/abg-dwarf-reader.h (abigail::dwarf::elf_type):
	Move this enum into the namespace abigail::elf_reader in the file
	include/abg-elf-reader.h.
	(abigail::dwarf::{read_context, read_context_sptr,
	create_read_context, read_context_get_path, reset_read_context,
	add_read_context_suppressions, set_read_context_corpus_group,
	read_corpus_from_elf, read_and_add_corpus_to_group_from_elf,
	read_and_add_corpus_to_group_from_elf,
	add_read_context_suppressions, refers_to_alt_debug_info,
	has_alt_debug_info, get_soname_of_elf_file, get_type_of_elf_file,
	set_debug_info_root_path, get_debug_info_root_path,
	get_show_stats, set_show_stats, set_drop_undefined_syms,
	set_do_log, set_environment, get_environment}): Remove.
	* src/abg-dwarf-reader.cc (struct dwfl_deleter, dwfl_sptr)
	(addr_elf_symbol_sptr_map_type, address_set_type)
	(address_set_sptr): Delete these types.
	(read_context::options_type): Remove.  The data members of this
	type got moved to struct fe_iface::options_type.
	(find_alt_debug_info_link, find_alt_debug_info_path)
	(find_alt_debug_info, lookup_data_tag_from_dynamic_segment)
	(elf_file_type, refers_to_alt_debug_info, has_alt_debug_info)
	(get_soname_of_elf_file, get_type_of_elf_file) : Remove these ELF
	specific functions from here; move them to the elf_reader
	namespace.
	(dwarf::reader): Create new class that extends
	elf_based_reader.  dwarf::read_context is renamed into this
	type, actually.
	(dwarf::reader::die_source_dependant_container_set::get_container):
	Adjust.
	(dwarf::reader::{supprs_, dwarf_version_,
	offline_callbacks_, debug_info_root_paths_, handle_, dwarf_,
	alt_fd_, alt_dwarf_, alt_debug_info_path_, elf_module_,
	elf_handle_, elf_path_, symtab_section_, cur_corpus_group_,
	cur_corpus_, dt_needed_, dt_soname_, elf_architecture_,
	exported_decls_builder_, options_, drop_undefined_syms_}): Remove
	these ELF-related data members to move them into the elf_reader
	namespace.
	(maybe_propagate_canonical_type)
	(build_translation_unit_and_add_to_ir, build_ir_node_from_die)
	(add_or_update_class_type, add_or_update_union_type)
	(build_ir_node_for_void_type)
	(build_ir_node_for_variadic_parameter_type, build_function_decl)
	(function_is_suppressed, build_or_get_fn_decl_if_not_suppressed)
	(build_var_decl, build_or_get_var_decl_if_not_suppressed)
	(variable_is_suppressed)
	(propagate_canonical_type)
	(get_parent_die, get_scope_die, die_is_at_class_scope)
	(die_location, die_qualified_type_name, die_qualified_name)
	(die_qualified_type_name_empty)
	(die_return_and_parm_names_from_fn_type_die)
	(die_function_signature, die_function_type_is_method_type)
	(die_pretty_print_type, die_pretty_print_decl, die_pretty_print)
	(maybe_canonicalize_type, build_subrange_type)
	(build_subranges_from_array_type_die, compare_dies, die_location)
	(die_loc_and_name, die_is_effectively_public_decl)
	(maybe_cache_type_comparison_result)
	(get_cached_type_comparison_result)
	(maybe_get_cached_type_comparison_result, die_is_at_class_scope)
	(die_function_type_is_method_type, die_member_offset)
	(die_qualified_type_name, die_qualified_decl_name)
	(die_qualified_name, die_qualified_type_name_empty)
	(die_return_and_parm_names_from_fn_type_die)
	(die_function_signature, die_pretty_print_type)
	(die_pretty_print_decl, die_pretty_print)
	(at_least_one_decl_only_among_odr_relevant_dies)
	(compare_as_type_dies, compare_as_decl_and_type_dies)
	(fn_die_equal_by_linkage_name, try_canonical_die_comparison)
	(maybe_propagate_canonical_type, propagate_canonical_type)
	(compare_dies, compare_dies_during_canonicalization)
	(find_import_unit_point_between_dies, get_parent_die)
	(get_scope_die, find_lower_bound_in_imported_unit_points)
	(build_translation_unit_and_add_to_ir)
	(build_namespace_decl_and_add_to_ir, build_type_decl)
	(build_enum_underlying_type, build_enum_type)
	(finish_member_function_reading)
	(maybe_finish_function_decl_reading)
	(lookup_class_or_typedef_from_corpus)
	(is_function_for_die_a_member_of_class)
	(add_or_update_member_function, add_or_update_class_type)
	(add_or_update_union_type, build_qualified_type)
	(schedule_array_tree_for_late_canonicalization)
	(maybe_strip_qualification, build_pointer_type_def)
	(build_reference_type, build_function_type, build_subrange_type)
	(build_subranges_from_array_type_die, build_array_type)
	(build_typedef_type, build_or_get_var_decl_if_not_suppressed)
	(build_var_decl, function_is_suppressed)
	(build_or_get_fn_decl_if_not_suppressed, variable_is_suppressed)
	(type_is_suppressed, type_is_suppressed)
	(get_opaque_version_of_type, create_default_fn_sym)
	(build_function_decl, maybe_canonicalize_type)
	(build_ir_node_from_die)
	(build_ir_node_for_variadic_parameter_type): Take a reference to
	the new dwarf::reader rather than to the previous
	read_context.  Adjust the function body.
	(return_comparison_result): Adjust.
	(dwarf::reader::reader): Adjust this from
	read_context::read_context.
	(dwarf::reader::initialize): Adjust from
	dwarf::read_context::initialize.
	(dwarf::reader::create): New factory static member
	function.
	(dwarf::reader::~reader): This doesn't have to clear
	anything for now.
	(dwarf::reader::read_corpus): New virtual member function
	which implements the fe_iface::read_corpus pure virtual interface.
	This now delegates the reading of the generic ELF properties to
	elf::reader by calling elf::reader::read_corpus().
	Newer front-ends will be able to do the same.
	(dwarf::reader::reset_corpus): New member function.
	(dwarf::reader::read_debug_info_into_corpus): Adjust.  This
	is now a member function.  Also, do not set the
	corpus::LINUX_KERNEL_BINARY_ORIGIN here as it's now set by the
	elf::reader when it loads the binary.
	(dwarf::reader::{env, drop_undefined_syms,
	drop_undefined_syms, dwarf_elf_handle, dwarf_per_die_source,
	elf_path, compute_canonical_die_offset, get_die_source,
	get_die_from_offset, get_die_qualified_name,
	get_die_pretty_type_representation, get_die_qualified_type_name,
	get_die_pretty_representation, odr_is_relevant,
	set_canonical_die_offset, get_canonical_die_offset,
	erase_canonical_die_offset, die_wip_classes_map,
	die_wip_function_types_map, compare_before_canonicalisation,
	resolve_declaration_only_classes, resolve_declaration_only_enums,
	symbol_already_belongs_to_a_function,
	fixup_functions_with_no_symbols, canonicalize_types_scheduled,
	tu_die_imported_unit_points_map, die_parent_map,
	find_symbol_table_section, get_variable_address,
	exported_decls_builder, load_all_types, load_in_linux_kernel_mode,
	show_stats, do_log, build_die_parent_maps): Adjust.
	(offset_pairs_stack_type::rdr_): Changed the ctxt_ into this.
	(offset_pairs_stack_type::offset_pairs_stack_type): Adjust.
	(offset_pairs_stack_type::{erase_redundant_type_pair_entry,
	cancel_canonical_propagated_type}): Adjust.
	(dwarf::reader::{get_suppressions, offline_callbacks,
	create_default_dwfl, dwfl_handle, elf_module, elf_handle,
	add_debug_info_root_paths, add_debug_info_root_path,
	find_alt_debug_info, dwarf, alt_dwarf, alt_debug_info_path,
	current_corpus, reset_current_corpus, current_corpus_group,
	has_corpus_group, main_corpus_from_current_group,
	current_corpus_is_main_corpus_from_current_group,
	should_reuse_type_from_corpus_group, function_symbol_is_exported,
	variable_symbol_is_exported, symtab, dt_needed, dt_soname,
	elf_architecture, is_elf_symbol_suppressed,
	load_dt_soname_and_needed, load_elf_architecture,
	load_elf_properties, maybe_add_fn_to_exported_decls,
	maybe_add_var_to_exported_decls}): Remove these member functions
	as they got moved into the elf_reader namespace or into the
	fe_iface class.
	(dwarf::read_context::{suppression_can_match,
	suppression_matches_function_sym_name,
	suppression_matches_function_name,
	suppression_matches_variable_name,
	suppression_matches_variable_sym_name,
	suppression_matches_type_name_or_location}): Move these into the
	suppr namespace.  Make it take an additional parameter that is
	reference fe_iface.
	(dwarf::reader::load_debug_info): Remove.  This became
	merged into dwarf::read_debug_info_into_corpus.
	(dwarf::{set_debug_info_root_path,
	get_debug_info_root_path, get_show_stats, set_drop_undefined_syms,
	set_do_log}): Remove.
	(add_read_context_suppressions)
	(set_read_context_corpus_group, read_corpus_from_elf): Remove.
	(read_debug_info_into_corpus): This became a member function of
	dwarf::reader.
	(create_reader): Renamed create_read_context into this.
	Make it return an elf_based_reader_sptr, like the other front-end
	factory functions.  Adjust.
	(reset_dwarf_reader): Renamed reset_read_context into this.
	Adjust.
	(read_corpus_from_elf): Adjust.
	* src/abg-elf-based-reader.cc: New file.
	* src/abg-elf-helpers.h (struct dwfl_deleter, dwfl_sptr)
	(addr_elf_symbol_sptr_map_type, address_set_sptr): Move these
	types here from abg-dwarf-reader.cc
	(initialize_dwfl_callbacks, lookup_data_tag_from_dynamic_segment):
	* src/abg-elf-helpers.cc (lookup_data_tag_from_dynamic_segment)
	(lookup_data_tag_from_dynamic_segment, initialize_dwfl_callbacks)
	(create_new_dwfl_handle, get_soname_of_elf_file): New functions
	that got moved here from the factorizing of abg-dwarf-reader.cc
	and abg-ctf-reader.cc.
	* src/abg-tools-utils.cc (file_has_dwarf_debug_info)
	(file_has_ctf_debug_info): New functions.
	(load_generate_apply_suppressions): Take an elf_based_reader, not
	a dwarf::read_context.
	(maybe_load_vmlinux_dwarf_corpus): Adjust the body to use the new
	front-end types.
	* src/Makefile.am: Add the new files src/abg-{fe-iface,
	elf-based-reader, elf-reader}.cc to source distribution. Remove
	src/abg-elf-reader-common.cc.
	* tools/Makefile.am: Factorize linking to libabigail.so by using
	LDADD.
	* tools/abicompat.cc (read_corpus, main): Adjust.
	* tools/abidiff.cc (set_suppressions)
	(set_native_xml_reader_options, handle_error, main): Adjust.
	* tools/abidw.cc (set_suppressions, load_corpus_and_write_abixml)
	(load_kernel_corpus_group_and_write_abixml): Adjust.
	* tools/abilint.cc (build_type_use_tree, show_how_type_is_used)
	(set_suppressions, main): Adjust.
	* tools/abipkgdiff.cc (elf_file::type, compare, compare_to_self)
	(create_maps_of_package_content)
	(compare_prepared_userspace_packages)
	(self_compare_prepared_userspace_package): Adjust.
	* tools/abisym.cc: Adjust invocation to
	abigail::dwarf::lookup_symbol_from_elf, from
	abigail::dwarf_reader::lookup_symbol_from_elf.
	* tools/kmidiff.cc (main): Adjust.
	* tests/print-diff-tree.cc (main): Adjust.
	* tests/test-abidiff.cc (main): Likewise.
	* tests/test-diff-dwarf.cc (main): Likewise.
	* tests/test-ir-walker.cc (main): Likewise.
	* tests/test-read-ctf.cc (test_task_ctf::perform): Likewise.
	* tests/test-read-dwarf.cc: Remove the useless "using" statements.
	* tests/test-read-write.cc: Likewise.
	* tests/test-symtab.cc (read_corpus, TEST_CASE)
	(assert_symbol_count): Adjust.
	* tests/data/test-read-ctf/test0.abi: Adjust.
	* tests/data/test-read-ctf/test0.hash.abi: Likewise.
	* tests/data/test-read-ctf/test1.so.abi: Likewise.
	* tests/data/test-read-ctf/test1.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test2.so.abi: Likewise.
	* tests/data/test-read-ctf/test2.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test3.so.abi: Likewise.
	* tests/data/test-read-ctf/test3.so.hash.abi: Likewise.
	* tests/data/test-read-ctf/test4.so.abi: Likewise.
	* tests/data/test-read-ctf/test4.so.hash.abi: Likewise.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 include/Makefile.am                        |    4 +-
 include/abg-corpus.h                       |   13 +-
 include/abg-ctf-reader.h                   |   32 +-
 include/abg-dwarf-reader.h                 |  129 +-
 include/abg-elf-based-reader.h             |   63 +
 include/abg-elf-reader-common.h            |   70 -
 include/abg-elf-reader.h                   |  161 +
 include/abg-fe-iface.h                     |  166 +
 include/abg-fwd.h                          |    5 +
 include/abg-reader.h                       |   55 +-
 include/abg-suppression.h                  |   67 +
 include/abg-tools-utils.h                  |   11 +
 src/Makefile.am                            |    4 +-
 src/abg-corpus-priv.h                      |   12 +-
 src/abg-corpus.cc                          |   15 +-
 src/abg-ctf-reader.cc                      | 1534 ++++----
 src/abg-dwarf-reader.cc                    | 3825 +++++++-------------
 src/abg-elf-based-reader.cc                |  102 +
 src/abg-elf-helpers.cc                     |  183 +-
 src/abg-elf-helpers.h                      |   38 +
 src/abg-elf-reader-common.cc               |   90 -
 src/abg-elf-reader.cc                      |  954 +++++
 src/abg-fe-iface.cc                        |  411 +++
 src/abg-ir.cc                              |   30 +-
 src/abg-reader.cc                          | 1902 +++++-----
 src/abg-suppression-priv.h                 |  179 -
 src/abg-suppression.cc                     |  479 ++-
 src/abg-tools-utils.cc                     |  154 +-
 tests/data/test-read-ctf/test0.abi         |    3 +
 tests/data/test-read-ctf/test0.hash.abi    |    3 +
 tests/data/test-read-ctf/test1.so.abi      |    3 +
 tests/data/test-read-ctf/test1.so.hash.abi |    3 +
 tests/data/test-read-ctf/test2.so.abi      |    3 +
 tests/data/test-read-ctf/test2.so.hash.abi |    3 +
 tests/data/test-read-ctf/test3.so.abi      |    5 +-
 tests/data/test-read-ctf/test3.so.hash.abi |    5 +-
 tests/data/test-read-ctf/test4.so.abi      |    3 +
 tests/data/test-read-ctf/test4.so.hash.abi |    3 +
 tests/print-diff-tree.cc                   |   19 +-
 tests/test-abidiff.cc                      |   21 +-
 tests/test-diff-dwarf.cc                   |   23 +-
 tests/test-ir-walker.cc                    |   11 +-
 tests/test-read-ctf.cc                     |   18 +-
 tests/test-read-dwarf.cc                   |    6 +-
 tests/test-read-write.cc                   |    3 -
 tests/test-symtab.cc                       |   39 +-
 tools/Makefile.am                          |   13 +-
 tools/abicompat.cc                         |   68 +-
 tools/abidiff.cc                           |  220 +-
 tools/abidw.cc                             |  157 +-
 tools/abilint.cc                           |  110 +-
 tools/abipkgdiff.cc                        |  200 +-
 tools/abisym.cc                            |    3 +-
 tools/kmidiff.cc                           |   11 +-
 54 files changed, 5981 insertions(+), 5663 deletions(-)
 create mode 100644 include/abg-elf-based-reader.h
 delete mode 100644 include/abg-elf-reader-common.h
 create mode 100644 include/abg-elf-reader.h
 create mode 100644 include/abg-fe-iface.h
 create mode 100644 src/abg-elf-based-reader.cc
 delete mode 100644 src/abg-elf-reader-common.cc
 create mode 100644 src/abg-elf-reader.cc
 create mode 100644 src/abg-fe-iface.cc
  

Patch

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 930f56de..75f6df7c 100644
--- a/include/abg-corpus.h
+++ b/include/abg-corpus.h
@@ -45,9 +45,10 @@  public:
   {
     ARTIFICIAL_ORIGIN = 0,
     NATIVE_XML_ORIGIN = 1,
-    DWARF_ORIGIN      = 1 << 1,
-    CTF_ORIGIN        = 1 << 2,
-    LINUX_KERNEL_BINARY_ORIGIN = 1 << 3
+    ELF_ORIGIN        = 1 << 1,
+    DWARF_ORIGIN      = 1 << 2,
+    CTF_ORIGIN        = 1 << 3,
+    LINUX_KERNEL_BINARY_ORIGIN = 1 << 4
   };
 
 private:
@@ -68,7 +69,7 @@  public:
   get_environment() const;
 
   void
-  add(const translation_unit_sptr);
+  add(const translation_unit_sptr&);
 
   const translation_units&
   get_translation_units() const;
@@ -326,10 +327,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.
diff --git a/include/abg-ctf-reader.h b/include/abg-ctf-reader.h
index 93d20973..79c50d75 100644
--- a/include/abg-ctf-reader.h
+++ b/include/abg-ctf-reader.h
@@ -17,40 +17,24 @@ 
 #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"
 
 namespace abigail
 {
-namespace ctf_reader
+namespace ctf
 {
 
-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_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,
+reset_reader(elf_based_reader&		ctxt,
+	     const std::string&	elf_path,
 	     const vector<char**>&	debug_info_root_path);
-std::string
-dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type);
 } // end namespace ctf_reader
 } // end namespace abigail
 
diff --git a/include/abg-dwarf-reader.h b/include/abg-dwarf-reader.h
index a127f7ce..f3682039 100644
--- a/include/abg-dwarf-reader.h
+++ b/include/abg-dwarf-reader.h
@@ -18,74 +18,37 @@ 
 #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
 {
 
 /// The namespace for the DWARF reader.
-namespace dwarf_reader
+namespace dwarf
 {
 
 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,
-		    const vector<char**>& debug_info_root_paths,
-		    ir::environment&	environment,
-		    bool		read_all_types = false,
-		    bool		linux_kernel_mode = false);
-
-const string&
-read_context_get_path(const read_context&);
+elf_based_reader_sptr
+create_reader(const std::string&	elf_path,
+	      const vector<char**>& debug_info_root_paths,
+	      environment&	environment,
+	      bool		read_all_types = false,
+	      bool		linux_kernel_mode = false);
 
 void
-reset_read_context(read_context_sptr &ctxt,
-		   const std::string&	elf_path,
-		   const vector<char**>& debug_info_root_paths,
-		   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_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(environment&			env,
@@ -99,61 +62,7 @@  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 dwarf
 
 }// 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..cf0c719e
--- /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
+{
+  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..86999ac1
--- /dev/null
+++ b/include/abg-elf-reader.h
@@ -0,0 +1,161 @@ 
+// 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
+{
+
+/// 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::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;
+
+  elf_symbol_sptr
+  function_symbol_is_exported(const string& name) const;
+
+  elf_symbol_sptr
+  variable_symbol_is_exported(const string& name) 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.
+typedef shared_ptr<elf::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.
+} // 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 33087b90..d5fcce7b 100644
--- a/include/abg-fwd.h
+++ b/include/abg-fwd.h
@@ -1440,6 +1440,11 @@  types_have_similar_structure(const type_base* first,
 			     const type_base* second,
 			     bool indirect_type = false);
 
+string
+build_internal_underlying_enum_type_name(const string &base_name,
+					 bool is_anonymous,
+					 uint64_t size);
+
 } // end namespace ir
 
 using namespace abigail::ir;
diff --git a/include/abg-reader.h b/include/abg-reader.h
index eb50482c..eb2a2f4d 100644
--- a/include/abg-reader.h
+++ b/include/abg-reader.h
@@ -17,17 +17,16 @@ 
 #include <istream>
 #include "abg-corpus.h"
 #include "abg-suppression.h"
+#include "abg-fe-iface.h"
 
 namespace abigail
 {
 
-namespace xml_reader
+namespace abixml
 {
 
 using namespace abigail::ir;
 
-class read_context;
-
 translation_unit_sptr
 read_translation_unit_from_file(const std::string&	file_path,
 				environment&		env);
@@ -41,61 +40,49 @@  read_translation_unit_from_istream(std::istream*	in,
 				   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_context_sptr
-create_native_xml_read_context(const string& path, environment& env);
+read_translation_unit(fe_iface&);
 
-read_context_sptr
-create_native_xml_read_context(std::istream* in, environment& env);
-const string&
-read_context_get_path(const read_context&);
+ abigail::fe_iface_sptr
+create_reader(const string& path, environment& env);
 
-corpus_sptr
-read_corpus_from_native_xml(std::istream* in,
-			    environment&  env);
+fe_iface_sptr
+create_reader(std::istream* in, environment& env);
 
 corpus_sptr
-read_corpus_from_native_xml_file(const string& path,
-				 environment&  env);
+read_corpus_from_abixml(std::istream* in,
+			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
 
 #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 c442c7c4..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 &);
@@ -313,6 +318,12 @@  build_corpus_group_from_kernel_dist_under(const string&	root,
 					  bool				verbose,
 					  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/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-corpus-priv.h b/src/abg-corpus-priv.h
index 74dc9448..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));
       }
   }
 
diff --git a/src/abg-corpus.cc b/src/abg-corpus.cc
index a42cbaa1..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;
@@ -611,10 +611,7 @@  const environment&
 corpus::get_environment() const
 {return priv_->env;}
 
-/// 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
@@ -622,7 +619,7 @@  corpus::get_environment() const
 ///
 /// @param tu the new translation unit to add.
 void
-corpus::add(const translation_unit_sptr tu)
+corpus::add(const translation_unit_sptr& tu)
 {
   ABG_ASSERT(priv_->members.insert(tu).second);
 
@@ -988,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.
diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
index 49dd69df..5fde94f3 100644
--- a/src/abg-ctf-reader.cc
+++ b/src/abg-ctf-reader.cc
@@ -23,39 +23,128 @@ 
 
 #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>
 
 namespace abigail
 {
-namespace ctf_reader
+namespace ctf
 {
 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,65 +238,487 @@  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) :
-   ir_env(env), ctfa(nullptr)
+  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);
+    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)
   {
-    types_map.clear();
-    filename = elf_path;
-    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::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;
   }
 
-  ~read_context()
+  /// 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;
+
+    corpus::origin origin = corpus()->get_origin();
+    origin |= corpus::CTF_ORIGIN;
+    corp->set_origin(origin);
+
+    if (corpus_group())
+      corpus_group()->add_corpus(corpus());
+
+    slurp_elf_info(status);
+    if (!elf_helpers::is_linux_kernel(elf_handle())
+	&& ((status & fe_iface::STATUS_DEBUG_INFO_NOT_FOUND) |
+	    (status & fe_iface::STATUS_NO_SYMBOLS_FOUND)))
+      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;
+  }
+
+  /// 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.
@@ -336,7 +727,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,
@@ -349,17 +740,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;
@@ -381,7 +772,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;
@@ -390,7 +781,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.
@@ -398,7 +789,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,
@@ -423,14 +814,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;
@@ -442,7 +833,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 */,
@@ -454,7 +845,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;
@@ -462,15 +853,15 @@  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;
+  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))
@@ -481,7 +872,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.
@@ -490,7 +881,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,
@@ -505,8 +896,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;
 
@@ -521,8 +912,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;
 
@@ -537,7 +928,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, "",
@@ -547,7 +938,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;
@@ -564,7 +955,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;
@@ -572,7 +963,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.
@@ -580,7 +971,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,
@@ -606,9 +997,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;
@@ -632,14 +1023,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)
@@ -653,24 +1044,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(),
@@ -684,14 +1075,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.
@@ -700,7 +1091,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,
@@ -712,12 +1103,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,
@@ -734,12 +1125,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;
@@ -747,7 +1138,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.
@@ -756,7 +1147,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,
@@ -768,12 +1159,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(),
@@ -788,12 +1179,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;
@@ -801,7 +1192,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.
@@ -810,7 +1201,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,
@@ -831,20 +1222,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;
@@ -863,7 +1254,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,
@@ -884,7 +1275,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;
@@ -892,14 +1283,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,
@@ -908,12 +1299,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;
@@ -937,7 +1328,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;
@@ -945,7 +1336,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.
@@ -954,7 +1345,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,
@@ -965,13 +1356,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;
@@ -983,7 +1374,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;
@@ -991,7 +1382,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.
@@ -1000,7 +1391,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)
@@ -1009,7 +1400,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;
 
@@ -1019,7 +1410,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,
@@ -1050,154 +1441,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;
 }
 
@@ -1256,162 +1502,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.
 ///
@@ -1419,13 +1509,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);
@@ -1436,326 +1527,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)
+elf_based_reader_sptr
+create_reader(const std::string& elf_path,
+	      const vector<char**>& debug_info_root_paths,
+	      environment& env)
 {
-  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)
-{
-  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.
@@ -1768,15 +1560,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,
+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);
+  ctf::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
@@ -1792,7 +1584,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;
@@ -1804,5 +1596,5 @@  dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type)
   return key.str();
 }
 
-} // End of namespace ctf_reader
+} // End of namespace ctf
 } // End of namespace abigail
diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index f07cb80e..bb9558d3 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>
@@ -56,7 +56,6 @@  ABG_END_EXPORT_DECLARATIONS
 #endif
 
 using std::string;
-using namespace abigail::elf_reader;
 
 namespace abigail
 {
@@ -64,7 +63,7 @@  namespace abigail
 using std::cerr;
 
 /// The namespace for the DWARF reader.
-namespace dwarf_reader
+namespace dwarf
 {
 
 using std::dynamic_pointer_cast;
@@ -91,16 +90,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 +132,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 +226,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 +363,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 +452,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 +494,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,
@@ -535,32 +519,27 @@  get_internal_anonymous_die_name(Dwarf_Die *die,
 				size_t anonymous_type_index);
 
 static string
-build_internal_underlying_enum_type_name(const string &base_name,
-					 bool is_anonymous,
-					 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 +550,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 +558,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 +566,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 +593,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.
 ///
@@ -1533,120 +1309,6 @@  lookup_public_function_symbol_from_elf(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 +1666,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::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(environment& e)
-      : env(e),
-	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 +1737,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 +1745,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 +1762,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 +1778,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 +1834,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 +1850,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 +1858,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 +1873,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,37 +1891,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)
-    : options_(environment)
+  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,
-	       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
@@ -2319,26 +1918,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,
-	     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 +1941,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,19 +1951,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_.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();
@@ -2392,27 +1965,348 @@  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);
   }
 
-  /// Detructor of the @ref read_context type.
-  ~read_context()
+  /// 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_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;
+  }
+
+  /// 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::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::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()->get_origin();
+    origin |= corpus::DWARF_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
@@ -2443,14 +2337,14 @@  public:
   /// @return the current environment.
   environment&
   env()
-  {return options_.env;}
+  {return options().env;}
 
   /// Getter for the current environment.
   ///
   /// @return the current environment.
   const environment&
   env() const
-  {return const_cast<read_context*>(this)->env();}
+  {return const_cast<reader*>(this)->env();}
 
   /// Getter for the flag that tells us if we are dropping functions
   /// and variables that have undefined symbols.
@@ -2459,7 +2353,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.
@@ -2467,67 +2361,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_;}
@@ -2536,47 +2372,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.
@@ -2585,7 +2383,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
@@ -2598,122 +2396,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:
@@ -2722,25 +2422,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
@@ -2807,9 +2494,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;
@@ -2874,13 +2561,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'.
     //
@@ -2955,9 +2643,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));
@@ -2972,9 +2660,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'.
@@ -3000,7 +2688,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))
 	  {
@@ -3047,9 +2735,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));
@@ -3069,9 +2757,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'.
@@ -3107,7 +2795,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))
 	  {
@@ -3190,10 +2878,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;
@@ -3218,9 +2906,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:
@@ -3323,8 +3013,8 @@  public:
 
     if (i == map.end())
       {
-	read_context& ctxt  = *const_cast<read_context*>(this);
-	string qualified_name = die_qualified_name(ctxt, die, where_offset);
+	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;
@@ -3348,7 +3038,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);
   }
 
@@ -3379,7 +3069,7 @@  public:
       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));
@@ -3388,7 +3078,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
@@ -3402,7 +3092,7 @@  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);
 	map[die_offset] = istr;
@@ -3434,7 +3124,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));
@@ -3442,9 +3132,9 @@  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);
+	  die_pretty_print_type(rdr, die, where_offset);
 	interned_string istr = env().intern(pretty_representation);
 	map[die_offset] = istr;
 	return istr;
@@ -3471,7 +3161,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));
@@ -3479,9 +3169,9 @@  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);
+	  die_pretty_print(rdr, die, where_offset);
 	interned_string istr = env().intern(pretty_representation);
 	map[die_offset] = istr;
 	return istr;
@@ -3696,7 +3386,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);
   }
 
@@ -3854,9 +3545,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,
@@ -3924,9 +3615,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);
@@ -3950,9 +3641,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);
@@ -3991,7 +3682,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.
   ///
@@ -4012,7 +3703,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.
   ///
@@ -4068,7 +3759,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
@@ -4105,7 +3796,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
@@ -4321,7 +4012,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;
 
@@ -4557,7 +4248,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;
 
@@ -4686,7 +4377,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;
 
@@ -4724,7 +4415,7 @@  public:
   void
   fixup_functions_with_no_symbols()
   {
-    corpus_sptr corp = current_corpus();
+    corpus_sptr corp = corpus();
     if (!corp)
       return;
 
@@ -4808,7 +4499,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.
@@ -4819,9 +4510,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();
       }
 
@@ -4842,7 +4533,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();
@@ -4862,9 +4553,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";
       }
   }
@@ -4940,7 +4631,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.
@@ -4967,127 +4658,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.
@@ -5097,7 +4673,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.
@@ -5202,11 +4778,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.
@@ -5237,70 +4809,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.
@@ -5339,94 +4847,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.
   ///
@@ -5661,159 +5081,12 @@  public:
     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))
-      return false;
-
-    return suppr::suppression_matches_type_name_or_location(s, type_name,
-							    type_location);
-  }
-
   /// Getter of the exported decls builder object.
   ///
   /// @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
@@ -5822,7 +5095,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
@@ -5831,15 +5104,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.
   ///
@@ -5849,7 +5122,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.
   ///
@@ -5859,7 +5132,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.
   ///
@@ -5869,44 +5142,16 @@  public:
   /// return the "do_log" flag.
   bool
   do_log() const
-  {return options_.do_log;}
-
-  /// Setter of the "do_log" flag.
-  ///
-  /// This flag tells if we should log about various internal details.
-  ///
-  /// @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);
-  }
+  {return options().do_log;}
 
-  /// If a given variable decl is suitable for the set of exported
-  /// variables of the current corpus, this variable adds it to that
-  /// set.
+  /// Setter of the "do_log" flag.
+  ///
+  /// This flag tells if we should log about various internal details.
   ///
-  /// @param fn the variable to consider for inclusion into the set of
-  /// exported variables of the current corpus.
+  /// @param f the new value of the flag.
   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);
-  }
+  do_log(bool f)
+  {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
@@ -6039,13 +5284,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;
@@ -6062,13 +5309,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);
 
@@ -6084,13 +5333,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 =
@@ -6107,7 +5358,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)
@@ -6115,7 +5367,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 =
@@ -6124,7 +5377,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.
 ///
@@ -6138,8 +5391,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_;
@@ -6153,8 +5406,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
@@ -6369,13 +5622,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);
   }
 
@@ -6406,32 +5659,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_++;
       }
   }
 
@@ -6469,7 +5722,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,
@@ -6478,13 +5731,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,
@@ -6494,7 +5747,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,
@@ -6503,25 +5756,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,
@@ -6529,20 +5782,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);
@@ -6551,78 +5804,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
 ///
@@ -6972,13 +6154,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();
@@ -6989,7 +6171,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;
     }
@@ -7010,7 +6192,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.
 ///
@@ -7020,13 +6202,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);
 }
@@ -7142,7 +6324,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))
@@ -7154,7 +6336,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);
@@ -7394,7 +6576,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.
 ///
@@ -7402,7 +6584,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)
@@ -7412,7 +6594,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;
 
@@ -7420,7 +6602,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.
 ///
@@ -7432,12 +6614,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;
@@ -7448,7 +6630,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.
 ///
@@ -7460,7 +6642,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)
@@ -7470,7 +6652,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;
@@ -7870,7 +7052,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.
 ///
@@ -7884,12 +7066,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);
@@ -8020,7 +7202,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.
 ///
@@ -8041,7 +7223,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,
@@ -8069,7 +7251,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
@@ -8082,7 +7264,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;
@@ -9433,14 +8615,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)
 {
@@ -9481,7 +8663,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;
 	}
     }
@@ -9498,7 +8680,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;
 
@@ -9664,29 +8846,6 @@  build_internal_anonymous_die_name(const string &base_name,
   return name;
 }
 
-/// Build the internal name of the underlying type of an enum.
-///
-/// @param base_name the (unqualified) name of the enum the underlying
-/// type is destined to.
-///
-/// @param is_anonymous true if the underlying type of the enum is to
-/// be anonymous.
-static string
-build_internal_underlying_enum_type_name(const string &base_name,
-					 bool is_anonymous,
-					 uint64_t size)
-{
-  std::ostringstream o;
-
-  if (is_anonymous)
-    o << "unnamed-enum";
-  else
-    o << "enum-" << base_name;
-
-  o << "-underlying-type-" << size;
-
-  return o.str();
-}
 
 /// Build a full internal anonymous type name.
 ///
@@ -9717,7 +8876,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.
 ///
@@ -9726,7 +8885,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)
 {
@@ -9742,10 +8901,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 ? "::" : ".";
 
@@ -9828,7 +8987,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";
 
@@ -9861,7 +9020,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())
@@ -9891,7 +9050,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();
@@ -9904,12 +9063,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);
 
@@ -9927,7 +9086,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,
@@ -9977,7 +9136,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.
 ///
@@ -9985,7 +9144,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)
 {
@@ -9995,10 +9154,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;
@@ -10012,7 +9171,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:
@@ -10038,7 +9197,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.
 ///
@@ -10046,12 +9205,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 "";
 }
 
@@ -10062,7 +9221,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.
 ///
@@ -10073,7 +9232,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)
 {
@@ -10096,19 +9255,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;
 
@@ -10126,7 +9285,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.
@@ -10152,7 +9311,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,
@@ -10169,22 +9328,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;
@@ -10215,8 +9374,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;
@@ -10240,11 +9399,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);
 	}
     }
 }
@@ -10252,7 +9411,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.
 ///
@@ -10261,14 +9420,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
@@ -10291,7 +9450,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())
@@ -10299,8 +9458,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;
@@ -10310,7 +9469,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);
@@ -10365,7 +9524,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.
 ///
@@ -10375,7 +9534,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)
 {
@@ -10405,17 +9564,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;
@@ -10428,13 +9587,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;
@@ -10443,7 +9602,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;
@@ -10451,7 +9610,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;
@@ -10462,12 +9621,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;
@@ -10485,7 +9644,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;
 
@@ -10498,7 +9657,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,
@@ -10507,7 +9666,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;
 
@@ -10532,7 +9691,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.
 ///
@@ -10542,7 +9701,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)
 {
@@ -10555,7 +9714,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:
@@ -10564,15 +9723,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:
@@ -10590,7 +9749,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.
 ///
@@ -10598,12 +9757,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 "";
 }
 
@@ -10667,7 +9826,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.
 ///
@@ -10676,11 +9835,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))
@@ -10703,7 +9862,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.
 ///
@@ -10711,7 +9870,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)
 {
@@ -10730,7 +9889,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;
@@ -10745,7 +9904,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.
 ///
@@ -10754,12 +9913,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;
@@ -10774,7 +9933,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.
 ///
@@ -10783,7 +9942,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)
 {
@@ -10802,8 +9961,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;
@@ -10824,7 +9983,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.
 ///
@@ -10847,7 +10006,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,
@@ -10857,20 +10016,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)
@@ -11077,7 +10236,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.
@@ -11085,7 +10244,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)
 {
@@ -11096,7 +10255,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
@@ -11106,7 +10265,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.
@@ -11114,7 +10273,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)
 {
@@ -11125,8 +10284,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));
@@ -11137,12 +10296,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));
 
 
@@ -11152,14 +10311,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_++;
     }
 }
 
@@ -11214,7 +10373,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?
@@ -11279,7 +10438,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;
@@ -11291,7 +10450,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.
 	}
     }
@@ -11333,7 +10492,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;
@@ -11341,7 +10500,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.
 ///
@@ -11363,7 +10522,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)
@@ -11371,8 +10530,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 =
     {
@@ -11398,7 +10557,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;
@@ -11411,7 +10570,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,
@@ -11436,7 +10595,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;
 
@@ -11448,7 +10607,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;
@@ -11485,14 +10644,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
 	{
@@ -11500,7 +10659,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),
@@ -11543,9 +10702,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
 	  {
@@ -11554,7 +10713,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;
@@ -11578,7 +10737,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);
 
@@ -11614,7 +10773,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;
@@ -11631,7 +10790,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)
@@ -11649,7 +10808,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)
@@ -11699,22 +10858,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
@@ -11727,7 +10886,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)))
@@ -11754,7 +10913,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)
@@ -11796,7 +10955,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);
@@ -11812,8 +10971,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);
 	    }
@@ -11824,7 +10983,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);
@@ -11839,7 +10998,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)
@@ -11857,8 +11016,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);
       }
@@ -11874,7 +11033,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)
@@ -11882,7 +11041,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)
@@ -11941,7 +11100,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;
@@ -11953,7 +11112,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.
 ///
@@ -11968,25 +11127,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.
 ///
@@ -11997,20 +11156,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)
 	{
@@ -12020,7 +11179,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;
@@ -12028,7 +11187,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);
 }
 
@@ -12039,7 +11198,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
@@ -12071,7 +11230,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,
@@ -12080,7 +11239,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);
@@ -12114,7 +11273,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,
@@ -12135,7 +11294,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,
@@ -12156,7 +11315,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
@@ -12174,7 +11333,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)
@@ -12182,7 +11341,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;
 
@@ -12192,7 +11351,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,
@@ -12218,7 +11377,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.
 ///
@@ -12233,16 +11392,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)));
 
@@ -12252,13 +11411,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:
@@ -12269,12 +11431,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);
@@ -12283,15 +11445,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);
 	}
     }
@@ -12310,7 +11472,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.
 ///
@@ -12319,12 +11481,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);
@@ -12335,15 +11497,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;
 }
@@ -12358,7 +11520,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.
 ///
@@ -12370,36 +11532,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
@@ -12410,7 +11572,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
@@ -12420,10 +11582,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;
@@ -12440,7 +11602,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))
@@ -12450,23 +11612,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())
@@ -12681,7 +11843,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.
 ///
@@ -12690,7 +11852,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)
 {
@@ -12702,9 +11864,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>")
@@ -12729,23 +11891,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)
@@ -12756,17 +11918,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))
@@ -12787,7 +11949,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)
 	      {
@@ -12817,7 +11979,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);
 
@@ -12831,7 +11993,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.
@@ -12844,7 +12006,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)
 {
@@ -12857,25 +12019,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
@@ -12884,14 +12046,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.
 ///
@@ -12899,7 +12061,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;
 
@@ -12918,21 +12080,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;
@@ -12942,19 +12104,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.
@@ -12965,7 +12127,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)
@@ -12974,11 +12136,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);
@@ -12988,7 +12150,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.
 ///
@@ -13001,7 +12163,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,
@@ -13017,7 +12179,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.
@@ -13032,7 +12194,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
@@ -13043,10 +12205,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);
@@ -13054,14 +12216,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;
 	}
     }
@@ -13087,7 +12249,7 @@  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(n, val));
@@ -13100,7 +12262,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);
 
@@ -13108,9 +12270,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;
 }
@@ -13127,12 +12289,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);
 
@@ -13229,7 +12391,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
@@ -13238,7 +12400,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())
@@ -13252,7 +12414,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.
 ///
@@ -13263,12 +12425,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);
 
@@ -13297,7 +12459,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.
@@ -13309,7 +12471,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)
@@ -13321,7 +12483,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)
@@ -13384,7 +12546,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.
 ///
@@ -13396,11 +12558,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();
@@ -13435,7 +12597,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.
@@ -13449,17 +12611,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));
@@ -13468,7 +12630,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;
 }
 
@@ -13483,7 +12645,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.
@@ -13509,7 +12671,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,
@@ -13522,7 +12684,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);
 
@@ -13531,8 +12693,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);
@@ -13542,7 +12704,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())
@@ -13560,7 +12722,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
@@ -13580,7 +12742,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
@@ -13598,7 +12760,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;
@@ -13620,7 +12782,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));
@@ -13662,16 +12824,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)
@@ -13685,13 +12847,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)
     {
@@ -13714,12 +12876,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));
 		}
@@ -13739,14 +12901,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);
@@ -13761,7 +12923,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
@@ -13778,19 +12940,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);
@@ -13826,18 +12988,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
@@ -13867,34 +13029,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.
 ///
@@ -13917,7 +13079,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,
@@ -13934,11 +13096,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);
@@ -13948,7 +13110,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())
@@ -13971,7 +13133,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);
@@ -13980,7 +13142,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;
 	    }
 	}
@@ -13993,7 +13155,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;
@@ -14007,7 +13169,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)
@@ -14024,23 +13186,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)
     {
@@ -14056,7 +13218,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
@@ -14067,7 +13229,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);
@@ -14093,14 +13255,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));
@@ -14110,31 +13272,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);
       }
   }
 
@@ -14144,7 +13306,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.
 ///
@@ -14159,7 +13321,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)
@@ -14181,10 +13343,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)
@@ -14192,10 +13354,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;
     }
 
@@ -14215,7 +13377,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;
 }
@@ -14231,22 +13393,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))
     {
@@ -14256,13 +13418,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);
     }
 }
 
@@ -14278,12 +13440,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;
@@ -14305,7 +13467,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();
@@ -14316,7 +13478,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);
@@ -14350,7 +13512,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);
 	}
     }
@@ -14360,7 +13522,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.
 ///
@@ -14375,7 +13537,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)
@@ -14395,12 +13557,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)
@@ -14408,7 +13570,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);
@@ -14421,7 +13583,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.
@@ -14429,19 +13591,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.
 ///
@@ -14456,7 +13618,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)
@@ -14476,7 +13638,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)
@@ -14484,7 +13646,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);
@@ -14497,29 +13659,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.
 ///
@@ -14534,7 +13696,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)
@@ -14547,12 +13709,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);
@@ -14562,21 +13724,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
@@ -14587,9 +13749,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;
 	}
     }
@@ -14602,7 +13764,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);
@@ -14620,7 +13782,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);
@@ -14637,20 +13799,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;
@@ -14665,7 +13827,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.
@@ -14675,7 +13837,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)
@@ -14692,7 +13854,7 @@  build_function_type(read_context&	ctxt,
 	    bool is_artificial = die_is_artificial(&child);
 
 	    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=*/"",
@@ -14717,23 +13879,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.
 ///
@@ -14754,8 +13916,8 @@  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,
-		    const Dwarf_Die*		die,
+build_subrange_type(reader&		rdr,
+		    const Dwarf_Die*	die,
 		    size_t		where_offset,
 		    bool		associate_type_to_die)
 {
@@ -14777,7 +13939,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));
@@ -14791,7 +13953,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;
@@ -14847,7 +14009,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,
@@ -14863,7 +14025,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;
 }
@@ -14872,7 +14034,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.
@@ -14885,7 +14047,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,
@@ -14907,7 +14069,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);
@@ -14916,7 +14078,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)
@@ -14929,7 +14091,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.
 ///
@@ -14944,7 +14106,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)
@@ -14962,7 +14124,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)
@@ -14970,7 +14132,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);
@@ -14982,7 +14144,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()));
 
@@ -14991,7 +14153,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.
 ///
@@ -15006,7 +14168,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)
@@ -15022,9 +14184,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);
 
@@ -15035,11 +14197,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));
@@ -15060,20 +14222,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.
 ///
@@ -15094,7 +14256,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,
@@ -15102,7 +14264,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))
@@ -15112,13 +14274,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.
 ///
@@ -15135,7 +14297,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)
@@ -15154,7 +14316,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)
@@ -15168,7 +14330,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));
@@ -15188,13 +14350,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)
@@ -15220,7 +14384,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.
 ///
@@ -15230,9 +14394,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)
@@ -15243,7 +14407,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);
 
@@ -15254,13 +14418,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())
@@ -15277,14 +14442,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
@@ -15300,7 +14464,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.
 ///
@@ -15323,7 +14487,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,
@@ -15331,7 +14495,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);
@@ -15355,11 +14519,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;
       }
 
@@ -15378,7 +14542,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;
 }
@@ -15387,7 +14551,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.
 ///
@@ -15398,9 +14562,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)
@@ -15412,7 +14576,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);
 
@@ -15424,10 +14588,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())
@@ -15444,16 +14609,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.
 ///
@@ -15466,9 +14632,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)
@@ -15482,10 +14648,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);
@@ -15493,9 +14660,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.
 ///
@@ -15503,14 +14670,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
@@ -15520,7 +14687,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.
 ///
@@ -15534,7 +14701,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)
@@ -15553,7 +14720,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;
 
@@ -15567,8 +14734,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)
@@ -15578,7 +14745,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,
@@ -15586,8 +14753,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;
 	}
     }
@@ -15595,8 +14762,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)
@@ -15605,7 +14772,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,
@@ -15649,7 +14816,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.
 ///
@@ -15661,7 +14828,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)
@@ -15674,16 +14841,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)
     {
@@ -15704,12 +14871,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,
@@ -15726,16 +14893,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();
@@ -15745,7 +14913,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);
 
@@ -15758,250 +14926,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.
@@ -16015,10 +14943,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;
@@ -16040,9 +14968,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);
 }
@@ -16112,10 +15040,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.
 ///
@@ -16144,7 +15072,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,
@@ -16161,7 +15089,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.  */;
@@ -16172,12 +15100,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())
@@ -16196,10 +15124,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;
@@ -16210,7 +15138,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);
 
@@ -16218,7 +15146,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;
@@ -16226,15 +15154,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;
@@ -16243,16 +15171,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;
@@ -16262,7 +15190,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)
@@ -16270,7 +15198,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);
@@ -16278,10 +15206,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;
@@ -16290,7 +15218,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
@@ -16299,19 +15227,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);
 	      }
 	  }
       }
@@ -16322,7 +15250,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)
 	  {
@@ -16332,8 +15260,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)
 	  {
@@ -16343,12 +15271,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,
@@ -16359,7 +15287,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,
@@ -16369,7 +15297,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,
@@ -16379,16 +15307,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,
@@ -16396,7 +15324,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;
 	}
@@ -16405,29 +15333,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;
       }
@@ -16437,13 +15365,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;
@@ -16471,7 +15399,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:
@@ -16481,21 +15409,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,
@@ -16507,26 +15435,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))
@@ -16536,8 +15464,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;
@@ -16571,7 +15499,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)
@@ -16582,7 +15510,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,
@@ -16603,14 +15531,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);
@@ -16633,18 +15561,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;
 
@@ -16709,11 +15637,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())
@@ -16724,46 +15652,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();
+  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();
+  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.
 ///
@@ -16782,7 +15712,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)
@@ -16790,10 +15720,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);
@@ -16808,34 +15738,35 @@  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.
 ///
-/// @param elf_path the path to the elf file the context is to be used for.
+/// @param elf_path the path to the elf file the reader is to be used
+/// for.
 ///
-/// @param debug_info_root_paths a pointer to the path to the root
-/// directory under which the debug info is to be found for @p
-/// elf_path.  Leave this to NULL if the debug info is not in a split
-/// file.
+/// @param debug_info_root_paths a vector to the paths to the
+/// directories under which the debug info is to be found for @p
+/// elf_path.  Pass an empty vector 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
+/// 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
@@ -16847,33 +15778,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,
-		    const vector<char**>&	debug_info_root_paths,
-		    ir::environment&		environment,
-		    bool			load_all_types,
-		    bool			linux_kernel_mode)
+/// @return a smart pointer to the resulting dwarf::reader.
+elf_based_reader_sptr
+create_reader(const std::string&		elf_path,
+	      const vector<char**>&	debug_info_root_paths,
+	      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.
@@ -16884,14 +15809,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
@@ -16903,136 +15828,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,
-		   bool		 read_all_types,
-		   bool		 linux_kernel_mode)
-{
-  if (ctxt)
-    ctxt->initialize(elf_path, debug_info_root_path,
-		     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.
 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_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
@@ -17051,7 +15857,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
@@ -17072,14 +15878,14 @@  read_corpus_from_elf(const std::string& elf_path,
 		     const vector<char**>& debug_info_root_paths,
 		     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::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
@@ -17171,219 +15977,6 @@  lookup_public_function_symbol_from_elf(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);
-  environment env;
-  read_context_sptr c = create_read_context(elf_path, di_roots, env);
-  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 dwarf
 
 }// 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..203e3412
--- /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(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::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..eedeaf8e
--- /dev/null
+++ b/src/abg-elf-reader.cc
@@ -0,0 +1,954 @@ 
+// 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
+{
+
+/// 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 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.
+  ///
+  /// @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::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 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 type.
+reader::~reader()
+{delete priv_;}
+
+/// Resets (erase) the resources used by the current @ref
+/// elf::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.
+///
+/// @return the 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.
+///
+/// @return the 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;
+}
+
+/// Test if a given function symbol has been exported.
+///
+/// @param name the name of the symbol we are looking for.
+///
+/// @return the elf symbol if found, or nil otherwise.
+elf_symbol_sptr
+reader::function_symbol_is_exported(const string& name) const
+{
+  const elf_symbols& syms = symtab()->lookup_symbol(name);
+  for (auto s : syms)
+    {
+      if (s->is_function() && s->is_public())
+	{
+	  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 (s->is_in_ksymtab())
+		return s;
+	    }
+	  else
+	    return s;
+	}
+    }
+  return elf_symbol_sptr();
+}
+
+/// Test if a given variable symbol has been exported.
+///
+/// @param name the name of the symbol we are looking
+/// for.
+///
+/// @return the elf symbol if found, or nil otherwise.
+elf_symbol_sptr
+reader::variable_symbol_is_exported(const string& name) const
+{
+  const elf_symbols& syms = symtab()->lookup_symbol(name);
+  for (auto s : syms)
+    {
+      if (s->is_variable() && s->is_public())
+	{
+	  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 (s->is_in_ksymtab())
+		return s;
+	    }
+	  else
+	    return s;
+	}
+    }
+  return elf_symbol_sptr();
+}
+/// 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;
+
+  corpus::origin origin = corpus()->get_origin();
+  origin |= corpus::ELF_ORIGIN;
+  if (is_linux_kernel(elf_handle()))
+    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
+  corpus()->set_origin(origin);
+
+  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::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::ELF_TYPE_PI_EXEC;
+      else
+	return elf::ELF_TYPE_DSO;
+    case ET_EXEC:
+      return elf::ELF_TYPE_EXEC;
+    case ET_REL:
+      return elf::ELF_TYPE_RELOCATABLE;
+    default:
+      return elf::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::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
+} // 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.cc b/src/abg-ir.cc
index f4b50cae..2476c3e1 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -1,5 +1,5 @@ 
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-// -*- mode: C++ -*-
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -*- mode:
+// C++ -*-
 //
 // Copyright (C) 2013-2022 Red Hat, Inc.
 //
@@ -28,11 +28,11 @@  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"
@@ -26244,6 +26244,30 @@  get_function_parameter(const decl_base* fun,
   return parms[parm_index].get();
 }
 
+/// Build the internal name of the underlying type of an enum.
+///
+/// @param base_name the (unqualified) name of the enum the underlying
+/// type is destined to.
+///
+/// @param is_anonymous true if the underlying type of the enum is to
+/// be anonymous.
+string
+build_internal_underlying_enum_type_name(const string &base_name,
+					 bool is_anonymous,
+					 uint64_t size)
+{
+  std::ostringstream o;
+
+  if (is_anonymous)
+    o << "unnamed-enum";
+  else
+    o << "enum-" << base_name;
+
+  o << "-underlying-type-" << size;
+
+  return o.str();
+}
+
 bool
 ir_traversable_base::traverse(ir_node_visitor&)
 {return true;}
diff --git a/src/abg-reader.cc b/src/abg-reader.cc
index 24b2ea30..31eb8fce 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
 {
 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,
+  reader(xml::reader_sptr reader,
 	 environment&	env)
-    : m_env(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,31 +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.
   environment&
   get_environment()
-  {return m_env;}
+  {return options().env;}
 
   /// Getter for the environment of this reader.
   ///
   /// @return the environment of this reader.
   const environment&
   get_environment() const
-  {return const_cast<read_context*>(this)->get_environment();}
+  {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
@@ -742,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.
@@ -782,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.
@@ -829,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,
@@ -840,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
@@ -916,8 +844,8 @@  public:
   void
   maybe_check_abixml_canonical_type_stability(type_base_sptr& t)
   {
-    if (!get_environment().self_comparison_debug_is_on()
-	|| get_environment().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))
@@ -929,15 +857,15 @@  public:
     // Let's get the type-id of this type as recorded in the
     // originating abixml file.
     string type_id =
-      get_environment().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 = get_environment().get_type_id_canonical_type_map().find(type_id);
-	if (j == get_environment().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: '"
@@ -1081,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())
@@ -1122,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.
   ///
@@ -1226,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&);
@@ -1257,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>
 //
@@ -1267,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.
@@ -1364,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.
@@ -1416,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;
@@ -1470,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);
@@ -1521,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());
 }
 
@@ -1534,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;
@@ -1550,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& rdr = dynamic_cast<abixml::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");
@@ -1588,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;
 }
@@ -1619,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;
@@ -1638,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();
@@ -1659,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& rdr = dynamic_cast<abixml::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;
 
@@ -1679,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")))
@@ -1692,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))
 	{
@@ -1706,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;
@@ -1729,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.
@@ -1739,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;
@@ -1773,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")))
@@ -1789,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;
       }
@@ -1842,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;
@@ -1877,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))
 	{
@@ -1893,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;
@@ -1918,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& rdr = dynamic_cast<abixml::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.
@@ -1954,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;
 }
@@ -1971,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
@@ -2009,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& rdr = dynamic_cast<abixml::reader&>(iface);
+  xml::reader_sptr reader = rdr.get_libxml_reader();
   if (!reader)
     return nil;
 
@@ -2227,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);
 
@@ -2254,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
@@ -2278,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_reader(in, env);
+  return read_corpus_group_from_input(*rdr);
 }
 
 /// De-serialize an ABI corpus group from an XML document file which
@@ -2300,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,
+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_reader(path, env);
+    corpus_group_sptr group = read_corpus_group_from_input(*rdr);
     return group;
 }
 
@@ -2321,10 +2176,10 @@  translation_unit_sptr
 read_translation_unit_from_file(const string&	input_file,
 				environment&	env)
 {
-  read_context ctxt(xml::new_reader_from_file(input_file), env);
-  translation_unit_sptr tu = read_translation_unit_from_input(ctxt);
+  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);
-  ctxt.perform_late_type_canonicalizing();
+  rdr.perform_late_type_canonicalizing();
   env.canonicalization_is_done(true);
   return tu;
 }
@@ -2343,10 +2198,10 @@  translation_unit_sptr
 read_translation_unit_from_buffer(const string&	buffer,
 				  environment&	env)
 {
-  read_context ctxt(xml::new_reader_from_buffer(buffer), env);
-  translation_unit_sptr tu = read_translation_unit_from_input(ctxt);
+  reader rdr(xml::new_reader_from_buffer(buffer), env);
+  translation_unit_sptr tu = read_translation_unit_from_input(rdr);
   env.canonicalization_is_done(false);
-  ctxt.perform_late_type_canonicalizing();
+  rdr.perform_late_type_canonicalizing();
   env.canonicalization_is_done(true);
   return tu;
 }
@@ -2354,17 +2209,18 @@  read_translation_unit_from_buffer(const string&	buffer,
 /// 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& rdr = dynamic_cast<abixml::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;
 }
 
@@ -2373,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);
@@ -2431,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)
 {
@@ -2448,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);
@@ -2470,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)
 {
@@ -2491,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);
@@ -2507,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.
 ///
@@ -2515,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;
@@ -3076,7 +2932,7 @@  maybe_map_type_with_type_id(const type_base_sptr& t,
   if (!t)
     return false;
 
-  const environment& env = t->get_environment();
+  const environment&env = t->get_environment();
   if (!env.self_comparison_debug_is_on()
       || is_non_canonicalized_type(t.get()))
     return false;
@@ -3093,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)
 {
@@ -3108,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);
     }
@@ -3119,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
@@ -3130,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)
 {
@@ -3138,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);
@@ -3150,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;
 }
@@ -3171,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.
 ///
@@ -3180,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;
@@ -3244,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,
@@ -3274,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.
 ///
@@ -3283,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;
 
@@ -3303,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)
@@ -3317,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.
 ///
@@ -3325,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)
 {
@@ -3343,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;
@@ -3353,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;
@@ -3407,7 +3263,7 @@  build_elf_symbol_db(read_context& ctxt,
 ///
 /// @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;
 
@@ -3432,11 +3288,11 @@  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);
 
@@ -3445,7 +3301,7 @@  build_function_parameter(read_context& ctxt, const xmlNodePtr node)
     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,
@@ -3456,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.
 ///
@@ -3473,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)
@@ -3502,13 +3358,14 @@  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();
   std::vector<function_decl::parameter_sptr> parms;
   type_base_sptr return_type = env.get_void_type();
 
@@ -3519,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")))
@@ -3529,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);
 	}
     }
 
@@ -3553,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;
 }
@@ -3577,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.
 ///
@@ -3595,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;
 }
@@ -3617,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.
@@ -3625,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"))
@@ -3635,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.
 ///
@@ -3686,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"))
@@ -3715,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.
 ///
@@ -3733,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)
 {
@@ -3767,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);
 
@@ -3782,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())
@@ -3809,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.
 ///
@@ -3819,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)
 {
@@ -3828,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);
@@ -3856,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.
@@ -3874,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;
     }
 
@@ -3891,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.
 ///
@@ -3901,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)
 {
@@ -3909,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);
@@ -3924,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;
@@ -3955,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);
@@ -3967,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.
 ///
@@ -3989,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)
 {
@@ -3999,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);
@@ -4012,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);
@@ -4023,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.
 ///
@@ -4065,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)
 {
@@ -4074,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);
@@ -4087,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);
@@ -4095,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);
 
@@ -4112,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;
 }
@@ -4135,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.
 ///
@@ -4145,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*/)
 {
@@ -4165,10 +4022,10 @@  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);
 
-  const environment& env = ctxt.get_environment();
+  const environment& env = rdr.get_environment();
   std::vector<shared_ptr<function_decl::parameter> > parms;
   type_base_sptr return_type = env.get_void_type();
 
@@ -4176,12 +4033,11 @@  build_function_type(read_context&	ctxt,
   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,
 					      /*is_const=*/false,
@@ -4189,9 +4045,9 @@  build_function_type(read_context&	ctxt,
 			    : 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;
@@ -4200,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")))
@@ -4210,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));
 	}
     }
@@ -4222,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.
@@ -4231,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;
@@ -4239,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);
@@ -4256,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);
@@ -4298,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.
@@ -4325,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;
@@ -4336,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.
 ///
@@ -4346,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)
 {
@@ -4356,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);
@@ -4369,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);
@@ -4386,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);
@@ -4419,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);
@@ -4428,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);
 	  }
@@ -4442,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
@@ -4496,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.
@@ -4509,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.
 ///
@@ -4531,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)
 {
@@ -4540,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);
@@ -4557,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);
@@ -4613,21 +4469,21 @@  build_enum_type_decl(read_context&	ctxt,
     }
 
   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;
     }
 
@@ -4636,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)
 {
@@ -4652,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);
@@ -4664,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);
@@ -4676,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.
 ///
@@ -4707,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;
 }
 
@@ -4721,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.
 ///
@@ -4730,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.
 ///
@@ -4753,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)
 {
@@ -4762,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);
@@ -4787,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;
@@ -4809,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);
@@ -4817,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
@@ -4849,7 +4705,7 @@  build_class_decl(read_context&		ctxt,
 	return previous_declaration;
     }
 
-  const environment& env = ctxt.get_environment();
+  const environment& env = rdr.get_environment();
 
   if (!is_decl_only && previous_definition)
     // We are in the case where we've read this class definition
@@ -4875,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;
@@ -4885,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;
@@ -4930,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;
@@ -4955,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()))
@@ -4986,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
@@ -5030,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))
 		    {
@@ -5040,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.
@@ -5062,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);
 			}
 		    }
 		}
@@ -5074,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
@@ -5102,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);
@@ -5121,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
@@ -5140,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
@@ -5150,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,
@@ -5163,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.
 ///
@@ -5181,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)
 {
@@ -5190,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);
@@ -5215,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;
@@ -5233,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
@@ -5265,7 +5121,7 @@  build_union_decl(read_context& ctxt,
 	return previous_declaration;
     }
 
-  const environment& env = ctxt.get_environment();
+  const environment& env = rdr.get_environment();
 
   if (!is_decl_only && previous_definition)
     // We are in the case where we've read this class definition
@@ -5287,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;
@@ -5298,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;
@@ -5343,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;
@@ -5359,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);
@@ -5397,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))
 		    {
@@ -5407,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,
@@ -5427,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);
 			}
 		    }
 		}
@@ -5439,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);
@@ -5455,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);
@@ -5471,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);
@@ -5487,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
@@ -5497,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,
@@ -5510,7 +5366,7 @@  build_union_decl(read_context& ctxt,
 	}
     }
 
-  ctxt.pop_scope_or_abort(decl);
+  rdr.pop_scope_or_abort(decl);
 
   return decl;
 }
@@ -5518,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.
 ///
@@ -5528,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)
 {
@@ -5540,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);
@@ -5552,12 +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();
+  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);
@@ -5565,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;
 }
@@ -5584,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.
 ///
@@ -5594,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)
 {
@@ -5606,21 +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();
+  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);
@@ -5628,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;
 }
@@ -5651,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.
 ///
@@ -5664,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)
@@ -5678,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;
@@ -5693,19 +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);
 
-
-  ctxt.maybe_canonicalize_type(result, /*force_delay=*/false);
+  rdr.maybe_canonicalize_type(result, /*force_delay=*/false);
 
   return result;
 }
@@ -5713,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.
 ///
@@ -5725,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)
@@ -5737,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);
@@ -5745,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;
@@ -5770,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.
 ///
@@ -5783,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)
@@ -5798,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;
@@ -5806,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;
@@ -5819,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.
 ///
@@ -5831,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)
@@ -5853,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;
@@ -5861,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;
@@ -5874,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;
@@ -5882,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;
@@ -5892,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.
 ///
@@ -5905,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);
@@ -5961,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;
 }
@@ -6234,8 +6089,8 @@  handle_class_tdecl(read_context&	ctxt,
 translation_unit_sptr
 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
@@ -6248,21 +6103,20 @@  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_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->corpus());
@@ -6271,7 +6125,7 @@  create_native_xml_read_context(const string& path, environment& env)
   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.
@@ -6279,14 +6133,13 @@  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_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->corpus());
@@ -6294,13 +6147,6 @@  create_native_xml_read_context(std::istream* in, environment& env)
   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'.
 ///
@@ -6314,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_reader(in, env);
+  fe_iface::status sts;
+  return rdr->read_corpus(sts);
 }
 
 /// De-serialize an ABI corpus from an XML document file which root
@@ -6335,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_reader(path, env);
+  fe_iface::status sts;
+  corpus_sptr corp = rdr->read_corpus(sts);
   return corp;
 }
 
@@ -6357,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;
@@ -6423,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-tools-utils.cc b/src/abg-tools-utils.cc
index 29700416..8898ef97 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 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 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
@@ -2542,15 +2592,16 @@  maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
   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,
-                                      /*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::create_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();
 
@@ -2561,7 +2612,7 @@  maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
 
   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 '"
@@ -2569,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)
@@ -2594,18 +2645,17 @@  maybe_load_vmlinux_dwarf_corpus(corpus::origin      origin,
          << "/" << total_nb_modules
          << ") ... " << std::flush;
 
-      reset_read_context(ctxt, *m, di_roots,
-                         /*read_all_types=*/false,
-                         /*linux_kernel_mode=*/true);
+      dwarf::reset_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 '"
@@ -2656,11 +2706,13 @@  maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
   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);
+  abigail::fe_iface::status status = abigail::fe_iface::STATUS_OK;
+  elf_based_reader_sptr rdr =
+    ctf::create_reader(vmlinux, di_roots, env);
+  ABG_ASSERT(rdr);
+
   group.reset(new corpus_group(env, root));
-  set_read_context_corpus_group(*ctxt, group);
+  rdr->corpus_group(group);
 
   if (verbose)
     std::cerr << "reading kernel binary '"
@@ -2668,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)
@@ -2693,12 +2745,11 @@  maybe_load_vmlinux_ctf_corpus(corpus::origin	  origin,
          << "/" << total_nb_modules
          << ") ... " << std::flush;
 
-      reset_read_context(ctxt, *m, di_roots);
-      set_read_context_corpus_group(*ctxt, group);
+      ctf::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 '"
@@ -2799,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::create_reader(elf_file_path,
+				  debug_info_root_paths,
+				  env);
+#ifdef WITH_CTF
+  else if (file_has_ctf_debug_info(elf_file_path, debug_info_root_paths))
+    result = ctf::create_reader(elf_file_path,
+				debug_info_root_paths,
+				env);
+#endif
+  else
+    result = dwarf::create_reader(elf_file_path,
+				  debug_info_root_paths,
+				  env);
+
+  return result;
+}
+
 }//end namespace tools_utils
 
 using abigail::ir::function_decl;
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 dce1c124..7b9c4df1 100644
--- a/tests/print-diff-tree.cc
+++ b/tests/print-diff-tree.cc
@@ -24,7 +24,6 @@  using abigail::comparison::compute_diff;
 using abigail::comparison::print_diff_tree;
 using abigail::comparison::apply_filters;
 using namespace abigail;
-using namespace abigail::dwarf_reader;
 
 struct options
 {
@@ -101,24 +100,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 env;
       vector<char**> di_roots;
-      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)
+      c1 = dwarf::read_corpus_from_elf(opts.elf1, di_roots, env,
+				       /*load_all_types=*/false,
+				       c1_status);
+      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,
-					      /*load_all_types=*/false,
-					      c2_status);
-      if (c2_status != elf_reader::STATUS_OK)
+      c2 = dwarf::read_corpus_from_elf(opts.elf2, di_roots, env,
+				       /*load_all_types=*/false,
+				       c2_status);
+      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 0e2b922b..83768262 100644
--- a/tests/test-abidiff.cc
+++ b/tests/test-abidiff.cc
@@ -171,15 +171,14 @@  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::comparison::corpus_diff_sptr;
 using abigail::comparison::translation_unit_diff_sptr;
 using abigail::comparison::compute_diff;
 using abigail::comparison::diff_context_sptr;
 using abigail::comparison::diff_context;
 
+using namespace abigail;
+
 int
 main(int, char*[])
 {
@@ -217,12 +216,12 @@  main(int, char*[])
       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);
+	tu1 = abixml::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);
+	corpus1 = abixml::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_nat