[1/1,RFC] Make Front Ends first class citizens

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

Commit Message

Dodji Seketeli Oct. 25, 2022, 3:19 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 infor 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 ABIBXML
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 inherits from 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 (properties of) the ABI corpus, corpus groups,
associated suppression specifications.  It also provides an abstract
interface to perform the actual loading of the ABI corpus.  That
abstract interface has 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::fe_iface
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::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::reader
re-uses the abigail::elf_reader::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::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::reader re-uses the
abigail::elf_reader::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::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 also simplifies how the environment is created and passed
around the functions that create front ends.  Basically, the
environment can simply be allocated on the stack and passed by
reference to the libabigail pipeline:

For instance:

    vector<char**> debug_info_paths;
    fe_iface::status result_status;
    abigail::ir::environment env;

    corpus_sptr abi_corpus = dwarf_reader::read_corpus_from_elf("/path/to/elf-binary",
								debug_info_paths, env,
								/*load_all_types=*/false,
								result_status);

    /* then do something with the resulting abi_corpus*/

Note how, you don't need to use the "new" operator to instantiate the
"env" object, of type environment.  It can sit on the stack, and it's
passed to the read_corpus_from_elf function by reference.

So, the internal representation types have been changed to refer to
the environment by reference, rather than requiring a pointer to it.

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

	* 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.
	* abg-fwd.h (type_or_void): Take a reference to the environment,
	not a pointer.
	* include/abg-ir.h (translation::translation): Take a reference to
	the environment, not a pointer.
	(translation::{g,s}et_environment): Return or take a reference to
	the environment, not a pointer.
	(elf_symbol::{elf_symbol, create, get_environment,
	set_environment}): Likewise.
	(type_or_decl_base::type_or_decl_base): Make the copy constructor
	private to prevent copy.
	(type_or_decl_base::operator=): Make this protected.
	(type_or_decl_base::{type_or_decl_base, get_environment,
	set_environment}): Return or take a reference to the environment,
	not a pointer.
	(set_environment_for_artifact): Remove this.  The environment is
	not set anymore after the artifact is created anymore.
	(decl_base::decl_base): Make the copy constructor protected.
	(decl_base::decl_base): In constructors, pass a reference to the
	environment, not a pointer.
	(scope_decl::scope_decl, type_base::type_base)
	(type_decl::type_decl, scope_type_decl::scope_type_decl)
	(namespace_decl::namespace_decl)
	(qualified_type_def::qualified_type_def)
	(pointer_type_def::pointer_type_def)
	(reference_type_def::reference_type_def)
	(array_type_def::subrange_type::subrange_type)
	(array_type_def::array_type_def)
	(enum_type_decl::enumerator::enumerator)
	(typedef_decl::typedef_decl, function_type::function_type)
	(method_type::method_type, template_decl::template_decl)
	(class_tdecl::class_tdecl, class_or_union::class_or_union)
	(class_decl::class_decl, union_decl::union_decl): Likewise.
	(enum_type_decl::enumerator::enumerator): Don't take a pointer to
	an environment anymore.
	(enum_type_decl::enumerator::get_environment): Remove.
	(enum_type_decl::enumerator::get_{name, qualified_name}): Return a
	string, no more an interned_string.  This is because the
	enumerator no more contains a pointer to an environment as no
	environment pointer is passed to ABI artifacts anymore.  The
	enumerator type can't have a reference to an environment because
	the enumerator is one of the rare types that is copyable in the
	IR, and the environment is not.  The sole purpose of the
	environment in the enumerator was to interning strings.  So
	enumerator are not the sole ABI artifact for which strings are not
	interned.  We'll see what the impact on performance is, but I
	expect it to be minimal.
	* src/abg-ir-priv.h (translation_unit::priv::env_): Turn the type
	of this into a reference to environment.
	(translation_unit::priv::priv): adjust.
	(environment::priv::{confirm_ct_propagation_for_types_dependant_on,
	confirm_ct_propagation, cancel_ct_propagation,
	mark_as_being_compared, unmark_as_being_compared,
	comparison_started, mark_as_being_compared, comparison_started}):
	* src/abg-ir.cc (class environment_setter): Remove.  This is now
	useless as the environment of ABI artifacts can no longer be
	modified.
	(push_composite_type_comparison_operands)
	(pop_composite_type_comparison_operands)
	(mark_dependant_types_compared_until, try_canonical_compare)
	(return_comparison_result, translation_unit::translation_unit)
	(translation_unit::{get_global_scope, get_environment,
	bind_function_type_life_time}): Adjust to use a reference to the
	environment, not a pointer.
	(translation_unit::set_environment): Remove.
	(elf_symbol::priv::env_): Turn the type of this into a reference
	to environment.
	(elf_symbol::priv::priv): Adjust to take a reference to the
	environment, not a pointer.
	(elf_symbol::elf_symbol): Remove the default constructor as it
	can't take a reference to an environment. Adjust the other
	constructor to make it take a reference to the environment, not a
	pointer.
	(elf_symbol::create): Remove the default one.  Adjust the other
	overload to make it take reference to the environment, not a
	pointer.
	(elf_symbol::get_environment): Adjust to return a reference to the
	environment, not a pointer.
	(elf_symbol::set_environment): Remove.
	(environment::get_void_type): Adjust.
	(type_or_decl_base::priv::env_): Make the type of this data member
	be reference to environment, not a pointer.
	(type_or_decl_base::{priv::priv, type_or_decl_base,
	get_environment, }): Adjust.
	(type_or_decl_base::{set_environment, operator=}): Remove.
	(set_environment_for_artifact): Remove.
	(decl_base::{decl_base, set_base, set_naming_typedef,
	set_linkage_name}, get_decl_name_for_comparison, strip_typedef)
	(strip_useless_const_qualification, scope_decl::{scope_decl,
	add_member_decl, get_generic_anonymous_internal_type_name})
	(get_type_name, get_name_of_pointer_to_type)
	(get_name_of_reference_to_type, get_name_of_qualified_type)
	(get_function_type_name, get_method_type_name)
	(is_void_pointer_type, lookup_basic_type)
	(lookup_union_type_per_location, lookup_enum_type)
	(lookup_typedef_type, lookup_pointer_type, lookup_type)
	(lookup_basic_type_per_location, lookup_class_type)
	(lookup_class_type_per_location, lookup_union_type)
	(lookup_enum_type, lookup_enum_types)
	(lookup_enum_type_per_location, lookup_typedef_type)
	(lookup_typedef_type_per_location, maybe_update_types_lookup_map)
	(maybe_update_types_lookup_map<class_decl>)
	(synthesize_type_from_translation_unit)
	(synthesize_function_type_from_translation_unit, type_or_void)
	(types_defined_same_linux_kernel_corpus_public)
	(compare_types_during_canonicalization)
	(type_base::{get_canonical_type_for, type_base::type_base,
	get_cached_pretty_representation}, type_decl::{type_decl,
	get_qualified_name}, scope_type_decl::scope_type_decl)
	(namespace_decl::namespace_decl, qualified_type_def::{build_name,
	qualified_type_def, get_qualified_name, set_underlying_type})
	(pointer_type_def::{priv::priv, pointer_type_def,
	set_pointed_to_type}, reference_type_def::reference_type_def)
	(array_type_def::{subrange_type::subrange_type, array_type_def,
	update_size, set_element_type, append_subranges, set_element_type,
	append_subranges, get_qualified_name, typedef_decl::typedef_decl})
	(equals, var_decl::{get_id, get_qualified_name})
	(function_type::function_type, method_type::method_type)
	(function_decl::{get_pretty_representation_of_declarator,
	set_symbol, get_id, parameter::get_type_name,
	parameter::get_type_pretty_representation,
	parameter::get_pretty_representation})
	(class_or_union::class_or_union, dump_classes_being_compared)
	(dump_fn_types_being_compared, copy_member_function)
	(maybe_propagate_canonical_type, class_decl::{class_decl,
	add_base_specifier}, maybe_cancel_propagated_canonical_type)
	(union_decl::union_decl, template_decl::template_decl)
	(function_tdecl::function_tdecl, class_tdecl::class_tdecl)
	(keep_type_alive, is_non_canonicalized_type)
	(qualified_name_setter::do_update): Adjust to take or use a
	reference of environment, not a pointer.
	(enum_type_decl::enumerator::priv::env_): Remove.  This can't have
	a reference to an environment because the
	enum_type_decl::enumerator type is copyable and the environment
	type is not.  So I am removing the environment data member from
	here.  The only reason why we had an environment as a data member
	here is so that the strings used by the enumerator type could be
	interned.  So for now, we are not interning those strings. That
	seems to incur no measurable speed cost so far.
	(enum_type_decl::enumerator::{priv::{name_, qualified_name}): Turn
	these into std::string, as opposed to interned_string.
	(enum_type_decl::enumerator::{priv::priv, enumerator, operator=,
	operator!=, get_name, get_qualified_name}): Adjust.
	(enum_type_decl::enumerator::get_environment): Remove.
	* 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_corpus_group_from_input): Take a reference to an
	environment, not a pointer.
	(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_abixml_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 that
	take a reference to environment.
	* src/abg-reader.cc (namespace abixml_reader): Rename the
	xml_reader namespace into this.
	(abixml_reader::reader_sptr): New typedef.
	(abixml_reader::reader): Rename read_context into this.  Make it
	inherit the fe_iface interface.
	(abixml_reader::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::reader::{reader, get_path, set_path,
	get_environment, get_exported_decls_builder,
	set_exported_decls_builder, get_suppressions,
	corpus_is_suppressed_by_soname_or_filename,
	suppression_can_match}): Adjust.
	(abixml_reader::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::reader::read_context().
	(abixml_reader::reader::get_libxml_reader): Rename the get_reader
	member function into this.
	(abixml_reader::add_reader_suppressions): Rename
	add_read_context_suppressions into this.
	(abixml_reader::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::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_corpus_group_from_abixml)
	(read_corpus_group_from_abixml_file)
	(read_translation_unit_from_buffer, maybe_map_type_with_type_id):
	Adjust.
	(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.
	(build_corpus_group_from_kernel_dist_under): Take a reference to
	environment, not a pointer.
	(create_best_elf_based_reader): Declare new function.
	* include/abg-writer.h (create_write_context): Take a reference to
	environment, not a pointer.
	* src/abg-comparison.cc (compute_diff): Stop asserting that
	artifacts being compared come from the same environment because
	now, it's less likely that things come from different environment,
	given that ABI artifacts can't see their environment changed.
	* 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.
	(corpus::{corpus,get_environment, set_environment})
	(corpus_group::{corpus_group}): Pass a reference to the
	environment, not a pointer.
	* src/abg-corpus-priv.h
	(corpus::exported_decls_builder::priv::add_{fn,var}_to_exported):
	Take a const parameter and adjust.
	(corpus::priv::env): Change the type of this from environment* to
	environment&.
	(corpus::priv::priv): Take a reference to environment, not a
	pointer.
	* src/abg-corpus.cc
	(corpus::exported_decls_builder::maybe_add_{fn,var}_to_exported_fns):
	Take a const parameter.
	(corpus::corpus): Take a reference to environment, not a pointer.
	(corpus::get_environment): Return a reference to environment, not
	a pointer.
	(corpus::set_environment): Remove.
	(corpus::add): Take a reference to translation_unit_sptr.
	(corpus::{record_type_as_reachable_from_public_interfaces,
	type_is_reachable_from_public_interfaces, init_format_version,
	is_empty}): Adjust use of reference to environment, rather than
	pointer.
	(corpus_group::corpus_group): Take a reference to environment, not
	a pointer.
	(corpus_group::add_corpus): Adjust use of reference to
	environment, rather than pointer.
	* 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_reader::{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_reader::{create_ctf_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::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_reader::read_context class.
	(ctf_reader::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::reader class.
	(ctf_reader::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::reader): This now takes a reference
	to an environment as opposed to a pointer, as far as the previous
	ctf_reader::read_context::read_context constructor was
	concerned.
	(ctf_reader::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_reader::{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_reader::read_context as first parameter.
	(lookup_type): Remove.  These are now member functions of the
	ctf_reader::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::reader rather an ctf_reader::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::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::reader.  Also, make it handle only CTF
	reader specific pieces.
	(create_read_context, read_corpus, set_read_context_corpus_group)
	(read_and_add_corpus_to_group_from_elf): Remove these functions.
	(create_ctf_reader, reset_reader): Create new functions
	(dic_type_key): Make this static.
	* include/abg-dwarf-reader.h (abigail::dwarf_reader::elf_type):
	Move this enum into the namespace abigail::elf_reader in the file
	include/abg-elf-reader.h.
	(abigail::dwarf_reader::{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::reader): Create new class that extends
	elf_based_reader.  dwarf_reader::read_context is renamed into this
	type, actually.
	(dwarf_reader::reader::die_source_dependant_container_set::get_container):
	Adjust.
	(dwarf_reader::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::reader rather than to the previous
	read_context.  Adjust the function body.
	(return_comparison_result): Adjust.
	(lookup_symbol_from_sysv_hash_tab)
	(lookup_symbol_from_gnu_hash_tab)
	(lookup_symbol_from_elf_hash_tab, lookup_symbol_from_symtab)
	(lookup_symbol_from_elf, lookup_public_function_symbol_from_elf):
	Take a reference to environment, rather than a pointer.
	(dwarf_reader::reader::reader): Adjust this from
	read_context::read_context.
	(dwarf_reader::reader::initialize): Adjust from
	dwarf_reader::read_context::initialize.
	(dwarf_reader::reader::create): New factory static member
	function.
	(dwarf_reader::reader::~reader): This doesn't have to clear
	anything for now.
	(dwarf_reader::reader::read_corpus): New virtual member function
	which implements the fe_iface::read_corpus pure virtual interface.
	(dwarf_reader::reader::reset_corpus): New member function.
	(dwarf_reader::reader::read_debug_info_into_corpus): Adjust.  This
	is now a member function.
	(dwarf_reader::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::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_reader::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::reader::load_debug_info): Remove.  This became
	merged into dwarf_reader::read_debug_info_into_corpus.
	(dwarf_reader::{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::reader.
	(create_dwarf_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, lookup_symbol_from_elf)
	(lookup_public_function_symbol_from_elf): Take a reference to the
	environment rather than a pointer.  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-symtab-reader.h (symtab::{load, load_}): Take a
	reference to an environment, not a pointer.
	* src/abg-symtab-reader.cc (symtab::{load, load_}): Likewise.
	* 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_reader::read_context.
	(maybe_load_vmlinux_dwarf_corpus)
	(build_corpus_group_from_kernel_dist_under): Take a reference to
	environment, not a pointer.  Adjust the body to use the new
	front-end types.
	* rc/abg-writer.cc (id_manger::m_env): Make this a reference to an
	environment, rather than a pointer.
	(id_manager::{id_manager, get_environment, get_id}): Adjust.
	(write_context::m_env): Make this a reference to an environment
	rather than a pointer.
	(write_context::{write_context, get_environment, get_config,
	get_id_for_type, decl_is_emitted, record_decl_as_emitted}):
	Adjust.
	(create_write_context, write_class_decl): Take a reference to an
	environment, rather than a pointer.  Adjust the body.
	* 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)
	(compare_prepared_linux_kernel_packages): Adjust.
	* tools/abisym.cc (main): Adjust.
	* 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                       |   18 +-
 include/abg-ctf-reader.h                   |   33 +-
 include/abg-dwarf-reader.h                 |  124 +-
 include/abg-elf-based-reader.h             |   63 +
 include/abg-elf-reader-common.h            |   70 -
 include/abg-elf-reader.h                   |  155 +
 include/abg-fe-iface.h                     |  166 +
 include/abg-fwd.h                          |    2 +-
 include/abg-ir.h                           |  156 +-
 include/abg-reader.h                       |   62 +-
 include/abg-suppression.h                  |   67 +
 include/abg-tools-utils.h                  |   13 +-
 include/abg-writer.h                       |    2 +-
 src/Makefile.am                            |    4 +-
 src/abg-comparison.cc                      |   67 +-
 src/abg-corpus-priv.h                      |   18 +-
 src/abg-corpus.cc                          |   73 +-
 src/abg-ctf-reader.cc                      | 1545 ++++----
 src/abg-dwarf-reader.cc                    | 3849 +++++++-------------
 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                      |  890 +++++
 src/abg-fe-iface.cc                        |  411 +++
 src/abg-ir-priv.h                          |   57 +-
 src/abg-ir.cc                              |  817 ++---
 src/abg-reader.cc                          | 1974 +++++-----
 src/abg-suppression-priv.h                 |  179 -
 src/abg-suppression.cc                     |  479 ++-
 src/abg-symtab-reader.cc                   |    5 +-
 src/abg-symtab-reader.h                    |    6 +-
 src/abg-tools-utils.cc                     |  163 +-
 src/abg-writer.cc                          |   39 +-
 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                   |   12 +-
 tests/test-abidiff.cc                      |   24 +-
 tests/test-diff-dwarf.cc                   |   20 +-
 tests/test-ir-walker.cc                    |    7 +-
 tests/test-read-ctf.cc                     |   20 +-
 tests/test-read-dwarf.cc                   |    3 -
 tests/test-read-write.cc                   |    3 -
 tests/test-symtab.cc                       |   42 +-
 tools/Makefile.am                          |   13 +-
 tools/abicompat.cc                         |   63 +-
 tools/abidiff.cc                           |  222 +-
 tools/abidw.cc                             |  178 +-
 tools/abilint.cc                           |  128 +-
 tools/abipkgdiff.cc                        |  222 +-
 tools/abisym.cc                            |    5 +-
 tools/kmidiff.cc                           |   14 +-
 61 files changed, 6365 insertions(+), 6569 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
  

Comments

Ben Woodard Oct. 31, 2022, 4:02 p.m. UTC | #1
Overall sounds like a good logical design.

On 10/25/22 08:19, Dodji Seketeli via Libabigail wrote:
> 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 infor 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 ABIBXML
> 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 inherits from 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 (properties of) the ABI corpus, corpus groups,

I follow you up to to the point where you get to corpus groups. It is 
not immediately obvious to me why corpus groups are included there. To 
me corpus groups are some sort of container of corpuses (or corpora - if 
you speak latin) not something that lives inside corpus fe_iface.

> associated suppression specifications.  It also provides an abstract
> interface to perform the actual loading of the ABI corpus.  That
> abstract interface has 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::fe_iface
> 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::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::reader
> re-uses the abigail::elf_reader::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::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::reader re-uses the
> abigail::elf_reader::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::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.

How about just calling it just abigail::abixml. There is also a abixml 
writer backend, and I think that having all that code in in one place 
would be good.

Furthermore, abixml isn't always the most handy format. It is certainly 
not very compact. If CTF or BTF are all that they claim to be, then 
maybe having a binary file format using them would be more compact. The 
thing is to make CTF and BTF stand alone and usable by other tools you 
would need to have a simple ELF wrapper around them similar to the 
.gnu_reflink split DWARF format for debuginfo. So it would probably make 
sense to have abigail::elf_based_handler (renamed from elf_based_reader) 
and then have the classes which can write multiple inherit from another 
abstract class like abigail::be-iface which contained the writing 
functions. Having the reading and writing code in the same class would 
be a clean design.

>
> 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 also simplifies how the environment is created and passed
> around the functions that create front ends.  Basically, the
> environment can simply be allocated on the stack and passed by
> reference to the libabigail pipeline:
>
> For instance:
>
>      vector<char**> debug_info_paths;
>      fe_iface::status result_status;
>      abigail::ir::environment env;
>
>      corpus_sptr abi_corpus = dwarf_reader::read_corpus_from_elf("/path/to/elf-binary",
> 								debug_info_paths, env,
> 								/*load_all_types=*/false,
> 								result_status);
>
>      /* then do something with the resulting abi_corpus*/
>
> Note how, you don't need to use the "new" operator to instantiate the
> "env" object, of type environment.  It can sit on the stack, and it's
> passed to the read_corpus_from_elf function by reference.
>
> So, the internal representation types have been changed to refer to
> the environment by reference, rather than requiring a pointer to it.
>
> The patch passes 'make distcheck' on all the supported platforms.
>
> 	* 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.
> 	* abg-fwd.h (type_or_void): Take a reference to the environment,
> 	not a pointer.
> 	* include/abg-ir.h (translation::translation): Take a reference to
> 	the environment, not a pointer.
> 	(translation::{g,s}et_environment): Return or take a reference to
> 	the environment, not a pointer.
> 	(elf_symbol::{elf_symbol, create, get_environment,
> 	set_environment}): Likewise.
> 	(type_or_decl_base::type_or_decl_base): Make the copy constructor
> 	private to prevent copy.
> 	(type_or_decl_base::operator=): Make this protected.
> 	(type_or_decl_base::{type_or_decl_base, get_environment,
> 	set_environment}): Return or take a reference to the environment,
> 	not a pointer.
> 	(set_environment_for_artifact): Remove this.  The environment is
> 	not set anymore after the artifact is created anymore.
> 	(decl_base::decl_base): Make the copy constructor protected.
> 	(decl_base::decl_base): In constructors, pass a reference to the
> 	environment, not a pointer.
> 	(scope_decl::scope_decl, type_base::type_base)
> 	(type_decl::type_decl, scope_type_decl::scope_type_decl)
> 	(namespace_decl::namespace_decl)
> 	(qualified_type_def::qualified_type_def)
> 	(pointer_type_def::pointer_type_def)
> 	(reference_type_def::reference_type_def)
> 	(array_type_def::subrange_type::subrange_type)
> 	(array_type_def::array_type_def)
> 	(enum_type_decl::enumerator::enumerator)
> 	(typedef_decl::typedef_decl, function_type::function_type)
> 	(method_type::method_type, template_decl::template_decl)
> 	(class_tdecl::class_tdecl, class_or_union::class_or_union)
> 	(class_decl::class_decl, union_decl::union_decl): Likewise.
> 	(enum_type_decl::enumerator::enumerator): Don't take a pointer to
> 	an environment anymore.
> 	(enum_type_decl::enumerator::get_environment): Remove.
> 	(enum_type_decl::enumerator::get_{name, qualified_name}): Return a
> 	string, no more an interned_string.  This is because the
> 	enumerator no more contains a pointer to an environment as no
> 	environment pointer is passed to ABI artifacts anymore.  The
> 	enumerator type can't have a reference to an environment because
> 	the enumerator is one of the rare types that is copyable in the
> 	IR, and the environment is not.  The sole purpose of the
> 	environment in the enumerator was to interning strings.  So
> 	enumerator are not the sole ABI artifact for which strings are not
> 	interned.  We'll see what the impact on performance is, but I
> 	expect it to be minimal.
> 	* src/abg-ir-priv.h (translation_unit::priv::env_): Turn the type
> 	of this into a reference to environment.
> 	(translation_unit::priv::priv): adjust.
> 	(environment::priv::{confirm_ct_propagation_for_types_dependant_on,
> 	confirm_ct_propagation, cancel_ct_propagation,
> 	mark_as_being_compared, unmark_as_being_compared,
> 	comparison_started, mark_as_being_compared, comparison_started}):
> 	* src/abg-ir.cc (class environment_setter): Remove.  This is now
> 	useless as the environment of ABI artifacts can no longer be
> 	modified.
> 	(push_composite_type_comparison_operands)
> 	(pop_composite_type_comparison_operands)
> 	(mark_dependant_types_compared_until, try_canonical_compare)
> 	(return_comparison_result, translation_unit::translation_unit)
> 	(translation_unit::{get_global_scope, get_environment,
> 	bind_function_type_life_time}): Adjust to use a reference to the
> 	environment, not a pointer.
> 	(translation_unit::set_environment): Remove.
> 	(elf_symbol::priv::env_): Turn the type of this into a reference
> 	to environment.
> 	(elf_symbol::priv::priv): Adjust to take a reference to the
> 	environment, not a pointer.
> 	(elf_symbol::elf_symbol): Remove the default constructor as it
> 	can't take a reference to an environment. Adjust the other
> 	constructor to make it take a reference to the environment, not a
> 	pointer.
> 	(elf_symbol::create): Remove the default one.  Adjust the other
> 	overload to make it take reference to the environment, not a
> 	pointer.
> 	(elf_symbol::get_environment): Adjust to return a reference to the
> 	environment, not a pointer.
> 	(elf_symbol::set_environment): Remove.
> 	(environment::get_void_type): Adjust.
> 	(type_or_decl_base::priv::env_): Make the type of this data member
> 	be reference to environment, not a pointer.
> 	(type_or_decl_base::{priv::priv, type_or_decl_base,
> 	get_environment, }): Adjust.
> 	(type_or_decl_base::{set_environment, operator=}): Remove.
> 	(set_environment_for_artifact): Remove.
> 	(decl_base::{decl_base, set_base, set_naming_typedef,
> 	set_linkage_name}, get_decl_name_for_comparison, strip_typedef)
> 	(strip_useless_const_qualification, scope_decl::{scope_decl,
> 	add_member_decl, get_generic_anonymous_internal_type_name})
> 	(get_type_name, get_name_of_pointer_to_type)
> 	(get_name_of_reference_to_type, get_name_of_qualified_type)
> 	(get_function_type_name, get_method_type_name)
> 	(is_void_pointer_type, lookup_basic_type)
> 	(lookup_union_type_per_location, lookup_enum_type)
> 	(lookup_typedef_type, lookup_pointer_type, lookup_type)
> 	(lookup_basic_type_per_location, lookup_class_type)
> 	(lookup_class_type_per_location, lookup_union_type)
> 	(lookup_enum_type, lookup_enum_types)
> 	(lookup_enum_type_per_location, lookup_typedef_type)
> 	(lookup_typedef_type_per_location, maybe_update_types_lookup_map)
> 	(maybe_update_types_lookup_map<class_decl>)
> 	(synthesize_type_from_translation_unit)
> 	(synthesize_function_type_from_translation_unit, type_or_void)
> 	(types_defined_same_linux_kernel_corpus_public)
> 	(compare_types_during_canonicalization)
> 	(type_base::{get_canonical_type_for, type_base::type_base,
> 	get_cached_pretty_representation}, type_decl::{type_decl,
> 	get_qualified_name}, scope_type_decl::scope_type_decl)
> 	(namespace_decl::namespace_decl, qualified_type_def::{build_name,
> 	qualified_type_def, get_qualified_name, set_underlying_type})
> 	(pointer_type_def::{priv::priv, pointer_type_def,
> 	set_pointed_to_type}, reference_type_def::reference_type_def)
> 	(array_type_def::{subrange_type::subrange_type, array_type_def,
> 	update_size, set_element_type, append_subranges, set_element_type,
> 	append_subranges, get_qualified_name, typedef_decl::typedef_decl})
> 	(equals, var_decl::{get_id, get_qualified_name})
> 	(function_type::function_type, method_type::method_type)
> 	(function_decl::{get_pretty_representation_of_declarator,
> 	set_symbol, get_id, parameter::get_type_name,
> 	parameter::get_type_pretty_representation,
> 	parameter::get_pretty_representation})
> 	(class_or_union::class_or_union, dump_classes_being_compared)
> 	(dump_fn_types_being_compared, copy_member_function)
> 	(maybe_propagate_canonical_type, class_decl::{class_decl,
> 	add_base_specifier}, maybe_cancel_propagated_canonical_type)
> 	(union_decl::union_decl, template_decl::template_decl)
> 	(function_tdecl::function_tdecl, class_tdecl::class_tdecl)
> 	(keep_type_alive, is_non_canonicalized_type)
> 	(qualified_name_setter::do_update): Adjust to take or use a
> 	reference of environment, not a pointer.
> 	(enum_type_decl::enumerator::priv::env_): Remove.  This can't have
> 	a reference to an environment because the
> 	enum_type_decl::enumerator type is copyable and the environment
> 	type is not.  So I am removing the environment data member from
> 	here.  The only reason why we had an environment as a data member
> 	here is so that the strings used by the enumerator type could be
> 	interned.  So for now, we are not interning those strings. That
> 	seems to incur no measurable speed cost so far.
> 	(enum_type_decl::enumerator::{priv::{name_, qualified_name}): Turn
> 	these into std::string, as opposed to interned_string.
> 	(enum_type_decl::enumerator::{priv::priv, enumerator, operator=,
> 	operator!=, get_name, get_qualified_name}): Adjust.
> 	(enum_type_decl::enumerator::get_environment): Remove.
> 	* 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_corpus_group_from_input): Take a reference to an
> 	environment, not a pointer.
> 	(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_abixml_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 that
> 	take a reference to environment.
> 	* src/abg-reader.cc (namespace abixml_reader): Rename the
> 	xml_reader namespace into this.
> 	(abixml_reader::reader_sptr): New typedef.
> 	(abixml_reader::reader): Rename read_context into this.  Make it
> 	inherit the fe_iface interface.
> 	(abixml_reader::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::reader::{reader, get_path, set_path,
> 	get_environment, get_exported_decls_builder,
> 	set_exported_decls_builder, get_suppressions,
> 	corpus_is_suppressed_by_soname_or_filename,
> 	suppression_can_match}): Adjust.
> 	(abixml_reader::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::reader::read_context().
> 	(abixml_reader::reader::get_libxml_reader): Rename the get_reader
> 	member function into this.
> 	(abixml_reader::add_reader_suppressions): Rename
> 	add_read_context_suppressions into this.
> 	(abixml_reader::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::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_corpus_group_from_abixml)
> 	(read_corpus_group_from_abixml_file)
> 	(read_translation_unit_from_buffer, maybe_map_type_with_type_id):
> 	Adjust.
> 	(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.
> 	(build_corpus_group_from_kernel_dist_under): Take a reference to
> 	environment, not a pointer.
> 	(create_best_elf_based_reader): Declare new function.
> 	* include/abg-writer.h (create_write_context): Take a reference to
> 	environment, not a pointer.
> 	* src/abg-comparison.cc (compute_diff): Stop asserting that
> 	artifacts being compared come from the same environment because
> 	now, it's less likely that things come from different environment,
> 	given that ABI artifacts can't see their environment changed.
> 	* 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.
> 	(corpus::{corpus,get_environment, set_environment})
> 	(corpus_group::{corpus_group}): Pass a reference to the
> 	environment, not a pointer.
> 	* src/abg-corpus-priv.h
> 	(corpus::exported_decls_builder::priv::add_{fn,var}_to_exported):
> 	Take a const parameter and adjust.
> 	(corpus::priv::env): Change the type of this from environment* to
> 	environment&.
> 	(corpus::priv::priv): Take a reference to environment, not a
> 	pointer.
> 	* src/abg-corpus.cc
> 	(corpus::exported_decls_builder::maybe_add_{fn,var}_to_exported_fns):
> 	Take a const parameter.
> 	(corpus::corpus): Take a reference to environment, not a pointer.
> 	(corpus::get_environment): Return a reference to environment, not
> 	a pointer.
> 	(corpus::set_environment): Remove.
> 	(corpus::add): Take a reference to translation_unit_sptr.
> 	(corpus::{record_type_as_reachable_from_public_interfaces,
> 	type_is_reachable_from_public_interfaces, init_format_version,
> 	is_empty}): Adjust use of reference to environment, rather than
> 	pointer.
> 	(corpus_group::corpus_group): Take a reference to environment, not
> 	a pointer.
> 	(corpus_group::add_corpus): Adjust use of reference to
> 	environment, rather than pointer.
> 	* 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_reader::{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_reader::{create_ctf_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::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_reader::read_context class.
> 	(ctf_reader::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::reader class.
> 	(ctf_reader::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::reader): This now takes a reference
> 	to an environment as opposed to a pointer, as far as the previous
> 	ctf_reader::read_context::read_context constructor was
> 	concerned.
> 	(ctf_reader::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_reader::{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_reader::read_context as first parameter.
> 	(lookup_type): Remove.  These are now member functions of the
> 	ctf_reader::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::reader rather an ctf_reader::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::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::reader.  Also, make it handle only CTF
> 	reader specific pieces.
> 	(create_read_context, read_corpus, set_read_context_corpus_group)
> 	(read_and_add_corpus_to_group_from_elf): Remove these functions.
> 	(create_ctf_reader, reset_reader): Create new functions
> 	(dic_type_key): Make this static.
> 	* include/abg-dwarf-reader.h (abigail::dwarf_reader::elf_type):
> 	Move this enum into the namespace abigail::elf_reader in the file
> 	include/abg-elf-reader.h.
> 	(abigail::dwarf_reader::{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::reader): Create new class that extends
> 	elf_based_reader.  dwarf_reader::read_context is renamed into this
> 	type, actually.
> 	(dwarf_reader::reader::die_source_dependant_container_set::get_container):
> 	Adjust.
> 	(dwarf_reader::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::reader rather than to the previous
> 	read_context.  Adjust the function body.
> 	(return_comparison_result): Adjust.
> 	(lookup_symbol_from_sysv_hash_tab)
> 	(lookup_symbol_from_gnu_hash_tab)
> 	(lookup_symbol_from_elf_hash_tab, lookup_symbol_from_symtab)
> 	(lookup_symbol_from_elf, lookup_public_function_symbol_from_elf):
> 	Take a reference to environment, rather than a pointer.
> 	(dwarf_reader::reader::reader): Adjust this from
> 	read_context::read_context.
> 	(dwarf_reader::reader::initialize): Adjust from
> 	dwarf_reader::read_context::initialize.
> 	(dwarf_reader::reader::create): New factory static member
> 	function.
> 	(dwarf_reader::reader::~reader): This doesn't have to clear
> 	anything for now.
> 	(dwarf_reader::reader::read_corpus): New virtual member function
> 	which implements the fe_iface::read_corpus pure virtual interface.
> 	(dwarf_reader::reader::reset_corpus): New member function.
> 	(dwarf_reader::reader::read_debug_info_into_corpus): Adjust.  This
> 	is now a member function.
> 	(dwarf_reader::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::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_reader::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::reader::load_debug_info): Remove.  This became
> 	merged into dwarf_reader::read_debug_info_into_corpus.
> 	(dwarf_reader::{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::reader.
> 	(create_dwarf_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, lookup_symbol_from_elf)
> 	(lookup_public_function_symbol_from_elf): Take a reference to the
> 	environment rather than a pointer.  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-symtab-reader.h (symtab::{load, load_}): Take a
> 	reference to an environment, not a pointer.
> 	* src/abg-symtab-reader.cc (symtab::{load, load_}): Likewise.
> 	* 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_reader::read_context.
> 	(maybe_load_vmlinux_dwarf_corpus)
> 	(build_corpus_group_from_kernel_dist_under): Take a reference to
> 	environment, not a pointer.  Adjust the body to use the new
> 	front-end types.
> 	* rc/abg-writer.cc (id_manger::m_env): Make this a reference to an
> 	environment, rather than a pointer.
> 	(id_manager::{id_manager, get_environment, get_id}): Adjust.
> 	(write_context::m_env): Make this a reference to an environment
> 	rather than a pointer.
> 	(write_context::{write_context, get_environment, get_config,
> 	get_id_for_type, decl_is_emitted, record_decl_as_emitted}):
> 	Adjust.
> 	(create_write_context, write_class_decl): Take a reference to an
> 	environment, rather than a pointer.  Adjust the body.
> 	* 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)
> 	(compare_prepared_linux_kernel_packages): Adjust.
> 	* tools/abisym.cc (main): Adjust.
> 	* 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                       |   18 +-
>   include/abg-ctf-reader.h                   |   33 +-
>   include/abg-dwarf-reader.h                 |  124 +-
>   include/abg-elf-based-reader.h             |   63 +
>   include/abg-elf-reader-common.h            |   70 -
>   include/abg-elf-reader.h                   |  155 +
>   include/abg-fe-iface.h                     |  166 +
>   include/abg-fwd.h                          |    2 +-
>   include/abg-ir.h                           |  156 +-
>   include/abg-reader.h                       |   62 +-
>   include/abg-suppression.h                  |   67 +
>   include/abg-tools-utils.h                  |   13 +-
>   include/abg-writer.h                       |    2 +-
>   src/Makefile.am                            |    4 +-
>   src/abg-comparison.cc                      |   67 +-
>   src/abg-corpus-priv.h                      |   18 +-
>   src/abg-corpus.cc                          |   73 +-
>   src/abg-ctf-reader.cc                      | 1545 ++++----
>   src/abg-dwarf-reader.cc                    | 3849 +++++++-------------
>   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                      |  890 +++++
>   src/abg-fe-iface.cc                        |  411 +++
>   src/abg-ir-priv.h                          |   57 +-
>   src/abg-ir.cc                              |  817 ++---
>   src/abg-reader.cc                          | 1974 +++++-----
>   src/abg-suppression-priv.h                 |  179 -
>   src/abg-suppression.cc                     |  479 ++-
>   src/abg-symtab-reader.cc                   |    5 +-
>   src/abg-symtab-reader.h                    |    6 +-
>   src/abg-tools-utils.cc                     |  163 +-
>   src/abg-writer.cc                          |   39 +-
>   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                   |   12 +-
>   tests/test-abidiff.cc                      |   24 +-
>   tests/test-diff-dwarf.cc                   |   20 +-
>   tests/test-ir-walker.cc                    |    7 +-
>   tests/test-read-ctf.cc                     |   20 +-
>   tests/test-read-dwarf.cc                   |    3 -
>   tests/test-read-write.cc                   |    3 -
>   tests/test-symtab.cc                       |   42 +-
>   tools/Makefile.am                          |   13 +-
>   tools/abicompat.cc                         |   63 +-
>   tools/abidiff.cc                           |  222 +-
>   tools/abidw.cc                             |  178 +-
>   tools/abilint.cc                           |  128 +-
>   tools/abipkgdiff.cc                        |  222 +-
>   tools/abisym.cc                            |    5 +-
>   tools/kmidiff.cc                           |   14 +-
>   61 files changed, 6365 insertions(+), 6569 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
>
> diff --git a/include/Makefile.am b/include/Makefile.am
> index b3b9148f..6b7f1e49 100644
> --- a/include/Makefile.am
> +++ b/include/Makefile.am
> @@ -4,8 +4,10 @@ abg-sptr-utils.h	\
>   abg-interned-str.h	\
>   abg-ir.h		\
>   abg-corpus.h		\
> +abg-fe-iface.h		\
> +abg-elf-based-reader.h  \
> +abg-elf-reader.h	\
>   abg-reader.h		\
> -abg-elf-reader-common.h \
>   abg-dwarf-reader.h	\
>   abg-writer.h		\
>   abg-comparison.h	\
> diff --git a/include/abg-corpus.h b/include/abg-corpus.h
> index 27de8c2f..20ec4f41 100644
> --- a/include/abg-corpus.h
> +++ b/include/abg-corpus.h
> @@ -60,21 +60,15 @@ public:
>     struct priv;
>     std::unique_ptr<priv> priv_;
>   
> -  corpus(ir::environment*, const string& path= "");
> +  corpus(const ir::environment&, const string& path= "");
>   
>     virtual ~corpus();
>   
> -  const environment*
> +  const environment&
>     get_environment() const;
>   
> -  environment*
> -  get_environment();
> -
> -  void
> -  set_environment(environment*);
> -
>     void
> -  add(const translation_unit_sptr);
> +  add(const translation_unit_sptr&);
>   
>     const translation_units&
>     get_translation_units() const;
> @@ -332,10 +326,10 @@ public:
>     exported_variables();
>   
>     void
> -  maybe_add_fn_to_exported_fns(function_decl*);
> +  maybe_add_fn_to_exported_fns(const function_decl*);
>   
>     void
> -  maybe_add_var_to_exported_vars(var_decl*);
> +  maybe_add_var_to_exported_vars(const var_decl*);
>   }; //corpus::exported_decls_builder
>   
>   /// Abstraction of a group of corpora.
> @@ -355,7 +349,7 @@ class corpus_group : public corpus
>   public:
>     typedef vector<corpus_sptr> corpora_type;
>   
> -  corpus_group(ir::environment*, const string&);
> +  corpus_group(const ir::environment&, const string&);
>   
>     virtual ~corpus_group();
>   
> diff --git a/include/abg-ctf-reader.h b/include/abg-ctf-reader.h
> index 0f49b5eb..ea19683e 100644
> --- a/include/abg-ctf-reader.h
> +++ b/include/abg-ctf-reader.h
> @@ -17,7 +17,7 @@
>   #include <ostream>
>   #include "abg-corpus.h"
>   #include "abg-suppression.h"
> -#include "abg-elf-reader-common.h"
> +#include "abg-elf-based-reader.h"
>   
>   #include "ctf-api.h"
>   
> @@ -26,32 +26,15 @@ namespace abigail
>   namespace ctf_reader
>   {
>   
> -class read_context;
> -typedef shared_ptr<read_context> read_context_sptr;
> -
> -read_context_sptr
> -create_read_context(const std::string& elf_path,
> -                    const vector<char**>& debug_info_root_paths,
> -                    ir::environment *env);
> -corpus_sptr
> -read_corpus(read_context *ctxt, elf_reader::status& status);
> -
> -corpus_sptr
> -read_corpus(const read_context_sptr &ctxt, elf_reader::status &status);
> -
> -corpus_sptr
> -read_and_add_corpus_to_group_from_elf(read_context*, corpus_group&, elf_reader::status&);
> -
> -void
> -set_read_context_corpus_group(read_context& ctxt, corpus_group_sptr& group);
> +elf_based_reader_sptr
> +create_ctf_reader(const std::string& elf_path,
> +		  const vector<char**>& debug_info_root_paths,
> +		  environment& env);
>   
>   void
> -reset_read_context(read_context_sptr &ctxt,
> -                   const std::string&	elf_path,
> -                   const vector<char**>& debug_info_root_path,
> -                   ir::environment*	environment);
> -std::string
> -dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type);
> +reset_reader(elf_based_reader&		ctxt,
> +	     const std::string&	elf_path,
> +	     const vector<char**>&	debug_info_root_path);
>   } // end namespace ctf_reader
>   } // end namespace abigail
>   
> diff --git a/include/abg-dwarf-reader.h b/include/abg-dwarf-reader.h
> index 5766f906..f325da32 100644
> --- a/include/abg-dwarf-reader.h
> +++ b/include/abg-dwarf-reader.h
> @@ -18,7 +18,7 @@
>   #include <elfutils/libdwfl.h>
>   #include "abg-corpus.h"
>   #include "abg-suppression.h"
> -#include "abg-elf-reader-common.h"
> +#include "abg-elf-based-reader.h"
>   
>   namespace abigail
>   {
> @@ -29,131 +29,39 @@ namespace dwarf_reader
>   
>   using namespace abigail::ir;
>   
> -/// The kind of ELF file we are looking at.
> -enum elf_type
> -{
> -  /// A normal executable binary
> -  ELF_TYPE_EXEC,
> -  /// A Position Independant Executable binary
> -  ELF_TYPE_PI_EXEC,
> -  /// A dynamic shared object, a.k.a shared library binrary.
> -  ELF_TYPE_DSO,
> -  /// A relocatalbe binary.
> -  ELF_TYPE_RELOCATABLE,
> -  /// An unknown kind of binary.
> -  ELF_TYPE_UNKNOWN
> -};
> -
> -class read_context;
> -
> -/// A convenience typedef for a smart pointer to a
> -/// dwarf_reader::read_context.
> -typedef shared_ptr<read_context> read_context_sptr;
> -
> -read_context_sptr
> -create_read_context(const std::string&	elf_path,
> +elf_based_reader_sptr
> +create_dwarf_reader(const std::string&	elf_path,
>   		    const vector<char**>& debug_info_root_paths,
> -		    ir::environment*	environment,
> +		    environment&	environment,
>   		    bool		read_all_types = false,
>   		    bool		linux_kernel_mode = false);
>   
> -const string&
> -read_context_get_path(const read_context&);
> -
>   void
> -reset_read_context(read_context_sptr &ctxt,
> -		   const std::string&	elf_path,
> -		   const vector<char**>& debug_info_root_paths,
> -		   ir::environment*	environment,
> -		   bool		read_all_types = false,
> -		   bool		linux_kernel_mode = false);
> -
> -void
> -add_read_context_suppressions(read_context& ctxt,
> -			      const suppr::suppressions_type& supprs);
> -
> -void
> -set_read_context_corpus_group(read_context& ctxt, corpus_group_sptr& group);
> +reset_dwarf_reader(elf_based_reader&		rdr,
> +		   const std::string&		elf_path,
> +		   const vector<char**>&	debug_info_root_paths,
> +		   bool			read_all_types = false,
> +		   bool			linux_kernel_mode = false);
>   
>   corpus_sptr
> -read_corpus_from_elf(read_context& ctxt, elf_reader::status& stat);
> -
> -corpus_sptr
> -read_corpus_from_elf(const std::string& elf_path,
> -		     const vector<char**>& debug_info_root_paths,
> -		     ir::environment*	environment,
> -		     bool		load_all_types,
> -		     elf_reader::status&);
> -
> -corpus_sptr
> -read_and_add_corpus_to_group_from_elf(read_context&, corpus_group&, elf_reader::status&);
> +read_corpus_from_elf(const std::string&	elf_path,
> +		     const vector<char**>&	debug_info_root_paths,
> +		     environment&		environment,
> +		     bool			load_all_types,
> +		     fe_iface::status&		status);
>   
>   bool
> -lookup_symbol_from_elf(const environment*		env,
> +lookup_symbol_from_elf(environment&			env,
>   		       const string&			elf_path,
>   		       const string&			symbol_name,
>   		       bool				demangle,
>   		       vector<elf_symbol_sptr>&	symbols);
>   
>   bool
> -lookup_public_function_symbol_from_elf(const environment*		env,
> +lookup_public_function_symbol_from_elf(environment&			env,
>   				       const string&			path,
>   				       const string&			symname,
>   				       vector<elf_symbol_sptr>&	func_syms);
> -
> -bool
> -refers_to_alt_debug_info(const read_context&	ctxt,
> -			 string&		alt_di_path);
> -
> -elf_reader::status
> -has_alt_debug_info(read_context&	ctxt,
> -		   bool&		has_alt_di,
> -		   string&		alt_debug_info_path);
> -
> -elf_reader::status
> -has_alt_debug_info(const string&	elf_path,
> -		   char**		debug_info_root_path,
> -		   bool&		has_alt_di,
> -		   string&		alt_debug_info_path);
> -
> -bool
> -get_soname_of_elf_file(const string& path, string& soname);
> -
> -bool
> -get_type_of_elf_file(const string& path, elf_type& type);
> -
> -
> -void
> -set_debug_info_root_path(read_context& ctxt,
> -			 char** path);
> -
> -char**
> -get_debug_info_root_path(read_context& ctxt,
> -			 char**& path);
> -
> -bool
> -get_show_stats(read_context& ctxt);
> -
> -void
> -set_show_stats(read_context& ctxt,
> -	       bool f);
> -
> -void
> -set_drop_undefined_syms(read_context& ctxt,
> -			bool f);
> -
> -void
> -set_do_log(read_context& ctxt, bool f);
> -
> -void
> -set_environment(read_context& ctxt,
> -		ir::environment*);
> -
> -const environment_sptr&
> -get_environment(const read_context& ctxt);
> -
> -environment_sptr&
> -get_environment(read_context& ctxt);
>   }// end namespace dwarf_reader
>   
>   }// end namespace abigail
> diff --git a/include/abg-elf-based-reader.h b/include/abg-elf-based-reader.h
> new file mode 100644
> index 00000000..8916822f
> --- /dev/null
> +++ b/include/abg-elf-based-reader.h
> @@ -0,0 +1,63 @@
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +// -*- Mode: C++ -*-
> +//
> +// Copyright (C) 2022 Red Hat, Inc.
> +//
> +// Author: Dodji Seketeli
> +
> +/// @file
> +///
> +/// This file contains the declarations for an elf-based.  DWARF and
> +/// CTF readers can inherit this one.
> +
> +
> +#ifndef __ABG_ELF_BASED_READER_H__
> +#define __ABG_ELF_BASED_READER_H__
> +
> +#include <memory>
> +#include <string>
> +
> +#include "abg-elf-reader.h"
> +#include "abg-corpus.h"
> +
> +namespace abigail
> +{
> +
> +/// The common interface of readers based on ELF.
> +///
> +/// These are for readers like DWARF and CTF readers that read debug
> +/// information describing binaries in the ELF format.
> +///
> +/// This interface extends the elf_reader::reader interface and thus
> +/// also provides facilities for reading ELF binaries.
> +class elf_based_reader : public elf_reader::reader
> +{
> +  struct priv;
> +  priv* priv_;
> +
> +  elf_based_reader() = delete;
> +
> +protected:
> +
> +  /// Readers that implement this interface must provide a factory
> +  /// method to create a reader instance as this constructor is
> +  /// protected.
> +  elf_based_reader(const std::string& elf_path,
> +		   const vector<char**>& debug_info_root_paths,
> +		   environment& env);
> +public:
> +
> +  ~elf_based_reader();
> +
> +  virtual void
> +  reset(const std::string& elf_path,
> +	const vector<char**>& debug_info_root_paths);
> +
> +  virtual ir::corpus_sptr
> +  read_and_add_corpus_to_group(ir::corpus_group& group,
> +			       fe_iface::status& status);
> +};//end class elf_based_reader
> +
> +typedef std::shared_ptr<elf_based_reader> elf_based_reader_sptr;
> +}// namespace
> +#endif
> diff --git a/include/abg-elf-reader-common.h b/include/abg-elf-reader-common.h
> deleted file mode 100644
> index 3f4d49b0..00000000
> --- a/include/abg-elf-reader-common.h
> +++ /dev/null
> @@ -1,70 +0,0 @@
> -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> -// -*- Mode: C++ -*-
> -//
> -// Copyright (C) 2021-2022 Oracle, Inc.
> -//
> -// Author: Jose E. Marchesi
> -
> -/// @file
> -///
> -/// This file contains declarations implementing the different status
> -/// in which a corpus read from an ELF file can result.  It is used by
> -/// the readers based on ELF files, such as DWARF and CTF.
> -///
> -/// More generally, this file contains declarations related to
> -/// facilities shared by the various readers that handle the ELF
> -/// format, e.g, the DWARF and CTF realder.
> -
> -#ifndef __ABG_ELF_READER_COMMON_H__
> -#define __ABG_ELF_READER_COMMON_H__
> -
> -#include <string>
> -
> -namespace abigail
> -{
> -
> -/// The namespace for an ELF based reader.
> -namespace elf_reader
> -{
> -
> -/// The status of the @ref read_corpus_from_elf() call.
> -enum status
> -{
> -  /// The status is in an unknown state
> -  STATUS_UNKNOWN = 0,
> -
> -  /// This status is for when the call went OK.
> -  STATUS_OK = 1,
> -
> -  /// This status is for when the debug info could not be read.
> -  STATUS_DEBUG_INFO_NOT_FOUND = 1 << 1,
> -
> -  /// This status is for when the alternate debug info could not be
> -  /// found.
> -  STATUS_ALT_DEBUG_INFO_NOT_FOUND = 1 << 2,
> -
> -  /// This status is for when the symbols of the ELF binaries could
> -  /// not be read.
> -  STATUS_NO_SYMBOLS_FOUND = 1 << 3,
> -};
> -
> -std::string
> -status_to_diagnostic_string(status s);
> -
> -status
> -operator|(status, status);
> -
> -status
> -operator&(status, status);
> -
> -status&
> -operator|=(status&, status);
> -
> -status&
> -operator&=(status&, status);
> -
> -}// end namespace elf_reader
> -
> -}// end namespace abigail
> -
> -#endif //__ABG_ELF_READER_COMMON_H__
> diff --git a/include/abg-elf-reader.h b/include/abg-elf-reader.h
> new file mode 100644
> index 00000000..c6cecf0f
> --- /dev/null
> +++ b/include/abg-elf-reader.h
> @@ -0,0 +1,155 @@
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +// -*- Mode: C++ -*-
> +//
> +// Copyright (C) 2022 Red Hat, Inc.
> +//
> +// Author: Dodji Seketeli
> +
> +/// @file
> +///
> +/// This file contains the declarations for the @ref fe_iface a.k.a
> +/// "Front End Interface".
> +
> +#ifndef __ABG_ELF_READER_H__
> +#define __ABG_ELF_READER_H__
> +
> +#include <memory>
> +#include <string>
> +
> +#include <elfutils/libdwfl.h>
> +
> +#include "abg-fe-iface.h"
> +#include "abg-ir.h"
> +#include "abg-suppression.h"
> +
> +namespace abigail
> +{
> +
> +/// The namespace for the ELF Reader.
> +namespace elf_reader
> +{
> +
> +/// The kind of ELF file we are looking at.
> +enum elf_type : unsigned
> +{
> +  /// A normal executable binary
> +  ELF_TYPE_EXEC,
> +  /// A Position Independant Executable binary
> +  ELF_TYPE_PI_EXEC,
> +  /// A dynamic shared object, a.k.a shared library binary.
> +  ELF_TYPE_DSO,
> +  /// A relocatalbe binary.
> +  ELF_TYPE_RELOCATABLE,
> +  /// An unknown kind of binary.
> +  ELF_TYPE_UNKNOWN
> +};
> +
> +/// This is the interface an ELF reader.
> +///
> +/// It knows how to open an ELF file, read its content and expose an
> +/// interface for its symbol table and other properties.
> +///
> +/// Note that the ABI corpus returned by the elf_reader::read_corpus()
> +/// member function doesn't contain any type representation.  It only
> +/// contains the representations of the the ELF symbols found in the
> +/// ELF file.
> +///
> +/// To construct the type representations for the functions and global
> +/// variables present in the ELF file, please use the implementations
> +/// of the @ref elf_based_reader interface.  Those know how to read
> +/// the debug information from the ELF file to build type
> +/// representation in the @ref abigail::ir::corpus instance.
> +class reader : public fe_iface
> +{
> +  struct priv;
> +  priv *priv_;
> +
> + public:
> +
> +  reader(const std::string&	elf_path,
> +	 const vector<char**>&	debug_info_roots,
> +	 environment&		env);
> +
> +  ~reader();
> +
> +  void
> +  reset(const std::string&	elf_path,
> +	 const vector<char**>&	debug_info_roots);
> +
> +  const vector<char**>&
> +  debug_info_root_paths() const;
> +
> +  const Dwfl_Callbacks&
> +  dwfl_offline_callbacks() const;
> +
> +  Dwfl_Callbacks&
> +  dwfl_offline_callbacks();
> +
> +  Elf*
> +  elf_handle() const;
> +
> +  const Dwarf*
> +  dwarf_debug_info() const;
> +
> +  const Dwarf*
> +  alternate_dwarf_debug_info() const;
> +
> +  const string&
> +  alternate_dwarf_debug_info_path() const;
> +
> +  bool
> +  refers_to_alt_debug_info(string& alt_di_path) const;
> +
> +  const Elf_Scn*
> +  find_symbol_table_section() const;
> +
> +  void
> +  reset_symbol_table_section();
> +
> +  const Elf_Scn*
> +  find_ctf_section() const;
> +
> +  const Elf_Scn*
> +  find_alternate_ctf_section() const;
> +
> +  const vector<string>&
> +  dt_needed()const;
> +
> +  const string&
> +  elf_architecture() const;
> +
> +  symtab_reader::symtab_sptr&
> +  symtab() const;
> +
> +  elf_symbol_sptr
> +  function_symbol_is_exported(GElf_Addr symbol_address) const;
> +
> +  elf_symbol_sptr
> +  variable_symbol_is_exported(GElf_Addr symbol_address) const;
> +
> +  void
> +  load_dt_soname_and_needed();
> +
> +  void
> +  load_elf_architecture();
> +
> +  void
> +  load_elf_properties();
> +
> +  virtual ir::corpus_sptr
> +  read_corpus(status& status);
> +};//end class reader.
> +
> +/// A convenience typedef for a smart pointer to a
> +/// elf_reader::reader.
> +typedef shared_ptr<elf_reader::reader> reader_sptr;
> +
> +bool
> +get_soname_of_elf_file(const string& path, string &soname);
> +
> +bool
> +get_type_of_elf_file(const string& path, elf_type& type);
> +} // end namespace elf_reader.
> +} // end namespace abigail
> +
> +#endif // __ABG_ELF_READER_H__
> diff --git a/include/abg-fe-iface.h b/include/abg-fe-iface.h
> new file mode 100644
> index 00000000..5e6cf26f
> --- /dev/null
> +++ b/include/abg-fe-iface.h
> @@ -0,0 +1,166 @@
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +// -*- Mode: C++ -*-
> +//
> +// Copyright (C) 2022 Red Hat, Inc.
> +//
> +// Author: Dodji Seketeli
> +
> +/// @file
> +///
> +/// This file contains the declarations for the @ref fe_iface a.k.a
> +/// "Front End Interface".
> +
> +#ifndef __ABG_FE_IFACE_H__
> +#define __ABG_FE_IFACE_H__
> +
> +#include "abg-ir.h"
> +#include "abg-suppression.h"
> +
> +namespace abigail
> +{
> +
> +/// The base class of all libabigail front-ends: The Front End Interface.
> +///
> +/// A front end reads a given type of binary format and constructs a
> +/// libagbigail internal representation from it.
> +///
> +/// The middle-end then manipulates that IR.
> +class fe_iface
> +{
> +protected:
> +  struct priv;
> +  priv* priv_;
> +
> + public:
> +
> +  /// The status of the @ref fe_iface::read_corpus call.
> +  enum status
> +  {
> +    /// The status is in an unknown state
> +    STATUS_UNKNOWN = 0,
> +
> +    /// This status is for when the call went OK.
> +    STATUS_OK = 1,
> +
> +    /// This status is for when the debug info could not be read.
> +    STATUS_DEBUG_INFO_NOT_FOUND = 1 << 1,
> +
> +    /// This status is for when the alternate debug info could not be
> +    /// found.
> +    STATUS_ALT_DEBUG_INFO_NOT_FOUND = 1 << 2,
> +
> +    /// This status is for when the symbols of the ELF binaries could
> +    /// not be read.
> +    STATUS_NO_SYMBOLS_FOUND = 1 << 3,
> +  };
> +
> +  /// The generic options that control the behaviour of all Front-End
> +  /// interfaces.
> +  struct options_type
> +  {
> +    environment&	env;
> +    bool		load_in_linux_kernel_mode	= false;
> +    bool		load_all_types			= false;
> +    bool		drop_undefined_syms		= false;
> +    bool		show_stats			= false;
> +    bool		do_log				= false;;
> +    options_type(environment&);
> +
> +  };// font_end_iface::options_type
> +
> +  fe_iface(const std::string& corpus_path, environment& e);
> +
> +  ~fe_iface();
> +
> +  void
> +  reset(const std::string& corpus_path, environment& e);
> +
> +  const options_type&
> +  options() const;
> +
> +  options_type&
> +  options();
> +
> +  const std::string&
> +  corpus_path() const;
> +
> +  void
> +  corpus_path(const std::string&);
> +
> +  const string&
> +  dt_soname() const;
> +
> +  void
> +  dt_soname(const string&);
> +
> +  bool
> +  load_in_linux_kernel_mode() const;
> +
> +  suppr::suppressions_type&
> +  suppressions();
> +
> +  const suppr::suppressions_type&
> +  suppressions() const;
> +
> +  void
> +  suppressions(suppr::suppressions_type&);
> +
> +  void
> +  add_suppressions(const suppr::suppressions_type&);
> +
> +  corpus_sptr
> +  corpus();
> +
> +  const corpus_sptr
> +  corpus() const;
> +
> +  corpus_group_sptr&
> +  corpus_group();
> +
> +  const corpus_group_sptr&
> +  corpus_group() const;
> +
> +  void
> +  corpus_group(const ir::corpus_group_sptr& cg);
> +
> +  bool
> +  has_corpus_group() const;
> +
> +  corpus_sptr
> +  main_corpus_from_current_group();
> +
> +  bool
> +  current_corpus_is_main_corpus_from_current_group();
> +
> +  corpus_sptr
> +  should_reuse_type_from_corpus_group();
> +
> +  void
> +  maybe_add_fn_to_exported_decls(const function_decl* fn);
> +
> +  void
> +  maybe_add_var_to_exported_decls(const var_decl* var);
> +
> +  virtual ir::corpus_sptr
> +  read_corpus(status& status) = 0;
> +}; //end class fe_iface
> +
> +typedef shared_ptr<fe_iface> fe_iface_sptr;
> +
> +std::string
> +status_to_diagnostic_string(fe_iface::status s);
> +
> +fe_iface::status
> +operator|(fe_iface::status, fe_iface::status);
> +
> +fe_iface::status
> +operator&(fe_iface::status, fe_iface::status);
> +
> +fe_iface::status&
> +operator|=(fe_iface::status&, fe_iface::status);
> +
> +fe_iface::status&
> +operator&=(fe_iface::status&, fe_iface::status);
> +
> +}// end namespace abigail
> +#endif // __ABG_FE_IFAC_H__
> diff --git a/include/abg-fwd.h b/include/abg-fwd.h
> index 1dbe99bb..33087b90 100644
> --- a/include/abg-fwd.h
> +++ b/include/abg-fwd.h
> @@ -1384,7 +1384,7 @@ string
>   demangle_cplus_mangled_name(const string&);
>   
>   type_base_sptr
> -type_or_void(const type_base_sptr, const environment*);
> +type_or_void(const type_base_sptr, const environment&);
>   
>   type_base_sptr
>   canonicalize(type_base_sptr);
> diff --git a/include/abg-ir.h b/include/abg-ir.h
> index 4892f0e2..4272a13c 100644
> --- a/include/abg-ir.h
> +++ b/include/abg-ir.h
> @@ -649,7 +649,7 @@ class translation_unit : public traversable_base
>     std::unique_ptr<priv> priv_;
>   
>     // Forbidden
> -  translation_unit() = delete;
> +  translation_unit();
>   
>   public:
>     /// Convenience typedef for a shared pointer on a @ref global_scope.
> @@ -689,21 +689,15 @@ public:
>     };
>   
>   public:
> -  translation_unit(const ir::environment*	env,
> +  translation_unit(const ir::environment&	env,
>   		   const std::string&		path,
>   		   char			address_size = 0);
>   
>     virtual ~translation_unit();
>   
> -  const environment*
> +  const environment&
>     get_environment() const;
>   
> -  environment*
> -  get_environment();
> -
> -  void
> -  set_environment(const environment*);
> -
>     language
>     get_language() const;
>   
> @@ -929,7 +923,7 @@ private:
>   
>     elf_symbol();
>   
> -  elf_symbol(const environment* e,
> +  elf_symbol(const environment& e,
>   	     size_t		i,
>   	     size_t		s,
>   	     const string&	n,
> @@ -952,30 +946,24 @@ private:
>   public:
>   
>     static elf_symbol_sptr
> -  create();
> -
> -  static elf_symbol_sptr
> -  create(const environment* e,
> -	 size_t		    i,
> -	 size_t		    s,
> -	 const string&	    n,
> -	 type		    t,
> -	 binding	    b,
> -	 bool		    d,
> -	 bool		    c,
> -	 const version&	    ve,
> -	 visibility	    vi,
> -	 bool		    is_in_ksymtab = false,
> +  create(const environment&	e,
> +	 size_t		i,
> +	 size_t		s,
> +	 const string&		n,
> +	 type			t,
> +	 binding		b,
> +	 bool			d,
> +	 bool			c,
> +	 const version&	ve,
> +	 visibility		vi,
> +	 bool			is_in_ksymtab = false,
>   	 const abg_compat::optional<uint64_t>&		crc = {},
>   	 const abg_compat::optional<std::string>&	ns = {},
> -	 bool		    is_suppressed = false);
> +	 bool						is_suppressed = false);
>   
> -  const environment*
> +  const environment&
>     get_environment() const;
>   
> -  void
> -  set_environment(const environment*) const;
> -
>     size_t
>     get_index() const;
>   
> @@ -1340,6 +1328,7 @@ class type_or_decl_base : public ir_traversable_base
>     mutable std::unique_ptr<priv> priv_;
>   
>     type_or_decl_base();
> +  type_or_decl_base(const type_or_decl_base&);
>   
>   protected:
>   
> @@ -1399,13 +1388,14 @@ protected:
>   
>     void hashing_started(bool) const;
>   
> +  type_or_decl_base&
> +  operator=(const type_or_decl_base&);
> +
>   public:
>   
> -  type_or_decl_base(const environment*,
> +  type_or_decl_base(const environment&,
>   		    enum type_or_decl_kind k = ABSTRACT_TYPE_OR_DECL);
>   
> -  type_or_decl_base(const type_or_decl_base&);
> -
>     virtual ~type_or_decl_base();
>   
>     bool
> @@ -1414,15 +1404,9 @@ public:
>     void
>     set_is_artificial(bool);
>   
> -  const environment*
> +  const environment&
>     get_environment() const;
>   
> -  environment*
> -  get_environment();
> -
> -  void
> -  set_environment(const environment*);
> -
>     void
>     set_artificial_location(const location &);
>   
> @@ -1447,9 +1431,6 @@ public:
>     translation_unit*
>     get_translation_unit();
>   
> -  type_or_decl_base&
> -  operator=(const type_or_decl_base&);
> -
>     virtual bool
>     traverse(ir_node_visitor&);
>   
> @@ -1511,14 +1492,6 @@ operator==(const type_or_decl_base_sptr&, const type_or_decl_base_sptr&);
>   bool
>   operator!=(const type_or_decl_base_sptr&, const type_or_decl_base_sptr&);
>   
> -void
> -set_environment_for_artifact(type_or_decl_base* artifact,
> -			     const environment* env);
> -
> -void
> -set_environment_for_artifact(type_or_decl_base_sptr artifact,
> -			     const environment* env);
> -
>   /// The base type of all declarations.
>   class decl_base : public virtual type_or_decl_base
>   {
> @@ -1591,23 +1564,22 @@ protected:
>   
>     void
>     set_context_rel(context_rel *c);
> +  decl_base(const decl_base&);
>   
>   public:
> -  decl_base(const environment* e,
> +  decl_base(const environment& e,
>   	    const string& name,
>   	    const location& locus,
>   	    const string& mangled_name = "",
>   	    visibility vis = VISIBILITY_DEFAULT);
>   
> -  decl_base(const environment* e,
> +  decl_base(const environment& e,
>   	    const interned_string& name,
>   	    const location& locus,
>   	    const interned_string& mangled_name = interned_string(),
>   	    visibility vis = VISIBILITY_DEFAULT);
>   
> -  decl_base(const environment*, const location&);
> -
> -  decl_base(const decl_base&);
> +  decl_base(const environment&, const location&);
>   
>     virtual bool
>     operator==(const decl_base&) const;
> @@ -1821,11 +1793,11 @@ protected:
>   public:
>     struct hash;
>   
> -  scope_decl(const environment* env,
> +  scope_decl(const environment& env,
>   	     const string& name, const location& locus,
>   	     visibility	vis = VISIBILITY_DEFAULT);
>   
> -  scope_decl(const environment* env, location& l);
> +  scope_decl(const environment& env, location& l);
>   
>     virtual size_t
>     get_hash() const;
> @@ -2000,7 +1972,7 @@ public:
>     /// runtime type of the type pointed to.
>     struct shared_ptr_hash;
>   
> -  type_base(const environment* e, size_t s, size_t a);
> +  type_base(const environment& e, size_t s, size_t a);
>   
>     friend type_base_sptr canonicalize(type_base_sptr);
>   
> @@ -2104,7 +2076,7 @@ public:
>     /// Facility to hash instance of type_decl
>     struct hash;
>   
> -  type_decl(const environment*	env,
> +  type_decl(const environment&	env,
>   	    const string&	name,
>   	    size_t		size_in_bits,
>   	    size_t		alignment_in_bits,
> @@ -2159,7 +2131,7 @@ public:
>     /// Hasher for instances of scope_type_decl
>     struct hash;
>   
> -  scope_type_decl(const environment* env, const string& name,
> +  scope_type_decl(const environment& env, const string& name,
>   		  size_t size_in_bits, size_t alignment_in_bits,
>   		  const location& locus, visibility vis = VISIBILITY_DEFAULT);
>   
> @@ -2180,7 +2152,7 @@ class namespace_decl : public scope_decl
>   {
>   public:
>   
> -  namespace_decl(const environment* env, const string& name,
> +  namespace_decl(const environment& env, const string& name,
>   		 const location& locus, visibility vis = VISIBILITY_DEFAULT);
>   
>     virtual string
> @@ -2234,7 +2206,7 @@ public:
>   
>     qualified_type_def(type_base_sptr type, CV quals, const location& locus);
>   
> -  qualified_type_def(environment* env, CV quals, const location& locus);
> +  qualified_type_def(const environment& env, CV quals, const location& locus);
>   
>     virtual size_t
>     get_size_in_bits() const;
> @@ -2335,10 +2307,9 @@ public:
>     pointer_type_def(const type_base_sptr& pointed_to_type, size_t size_in_bits,
>   		   size_t alignment_in_bits, const location& locus);
>   
> -  pointer_type_def(environment* env, size_t size_in_bits,
> +  pointer_type_def(const environment& env, size_t size_in_bits,
>   		   size_t alignment_in_bits, const location& locus);
>   
> -
>     void
>     set_pointed_to_type(const type_base_sptr&);
>   
> @@ -2400,7 +2371,7 @@ public:
>   		     bool lvalue, size_t size_in_bits,
>   		     size_t alignment_in_bits, const location& locus);
>   
> -  reference_type_def(const environment* env, bool lvalue, size_t size_in_bits,
> +  reference_type_def(const environment& env, bool lvalue, size_t size_in_bits,
>   		     size_t alignment_in_bits, const location& locus);
>   
>     void
> @@ -2522,7 +2493,7 @@ public:
>       /// Hasher for an instance of array::subrange
>       struct hash;
>   
> -    subrange_type(const environment*	env,
> +    subrange_type(const environment&	env,
>   		  const string&	name,
>   		  bound_value		lower_bound,
>   		  bound_value		upper_bound,
> @@ -2530,14 +2501,14 @@ public:
>   		  const location&	loc,
>   		  translation_unit::language l = translation_unit::LANG_C11);
>   
> -    subrange_type(const environment* env,
> +    subrange_type(const environment& env,
>   		  const string& name,
>   		  bound_value lower_bound,
>   		  bound_value upper_bound,
>   		  const location& loc,
>   		  translation_unit::language l = translation_unit::LANG_C11);
>   
> -    subrange_type(const environment* env,
> +    subrange_type(const environment& env,
>   		  const string& name,
>   		  bound_value upper_bound,
>   		  const location& loc,
> @@ -2603,7 +2574,7 @@ public:
>   		 const std::vector<subrange_sptr>& subs,
>   		 const location& locus);
>   
> -  array_type_def(environment* env,
> +  array_type_def(const environment& env,
>   		 const std::vector<subrange_sptr>& subs,
>   		 const location& locus);
>   
> @@ -2761,7 +2732,7 @@ public:
>   
>     ~enumerator();
>   
> -  enumerator(const environment* env, const string& name, int64_t value);
> +  enumerator(const string& name, int64_t value);
>   
>     enumerator(const enumerator&);
>   
> @@ -2774,13 +2745,10 @@ public:
>     bool
>     operator!=(const enumerator& other) const;
>   
> -  const environment*
> -  get_environment() const;
> -
> -  const interned_string&
> +  const string&
>     get_name() const;
>   
> -  const interned_string&
> +  const string&
>     get_qualified_name(bool internal = false) const;
>   
>     void
> @@ -2823,7 +2791,7 @@ public:
>   	       visibility vis = VISIBILITY_DEFAULT);
>   
>     typedef_decl(const string& name,
> -	       environment* env,
> +	       const environment& env,
>   	       const location& locus,
>   	       const string& mangled_name = "",
>   	       visibility vis = VISIBILITY_DEFAULT);
> @@ -3320,7 +3288,7 @@ public:
>   		size_t		size_in_bits,
>   		size_t		alignment_in_bits);
>   
> -  function_type(const environment*	env,
> +  function_type(const environment&	env,
>   		size_t		size_in_bits,
>   		size_t		alignment_in_bits);
>   
> @@ -3415,7 +3383,7 @@ public:
>   	      size_t size_in_bits,
>   	      size_t alignment_in_bits);
>   
> -  method_type(const environment* env,
> +  method_type(const environment& env,
>   	      size_t size_in_bits,
>   	      size_t alignment_in_bits);
>   
> @@ -3452,7 +3420,7 @@ public:
>     /// Hasher.
>     struct hash;
>   
> -  template_decl(const environment*	env,
> +  template_decl(const environment&	env,
>   		const string&		name,
>   		const location&	locus,
>   		visibility		vis = VISIBILITY_DEFAULT);
> @@ -3683,7 +3651,7 @@ public:
>     struct hash;
>     struct shared_ptr_hash;
>   
> -  function_tdecl(const environment*	env,
> +  function_tdecl(const environment&	env,
>   		 const location&	locus,
>   		 visibility		vis = VISIBILITY_DEFAULT,
>   		 binding		bind = BINDING_NONE);
> @@ -3732,7 +3700,7 @@ public:
>     struct hash;
>     struct shared_ptr_hash;
>   
> -  class_tdecl(const environment* env, const location& locus,
> +  class_tdecl(const environment& env, const location& locus,
>   	      visibility vis = VISIBILITY_DEFAULT);
>   
>     class_tdecl(class_decl_sptr	pattern,
> @@ -3953,17 +3921,17 @@ public:
>     typedef unordered_map<string, method_decl_sptr> string_mem_fn_sptr_map_type;
>     /// @}
>   
> -  class_or_union(const environment* env, const string& name,
> +  class_or_union(const environment& env, const string& name,
>   		 size_t size_in_bits, size_t align_in_bits,
>   		 const location& locus, visibility vis,
>   		 member_types& mbrs, data_members& data_mbrs,
>   		 member_functions& member_fns);
>   
> -  class_or_union(const environment* env, const string& name,
> +  class_or_union(const environment& env, const string& name,
>   		 size_t size_in_bits, size_t align_in_bits,
>   		 const location& locus, visibility vis);
>   
> -  class_or_union(const environment* env, const string& name,
> +  class_or_union(const environment& env, const string& name,
>   		 bool is_declaration_only = true);
>   
>     virtual void
> @@ -4159,30 +4127,30 @@ private:
>   
>   public:
>   
> -  class_decl(const environment* env, const string& name,
> +  class_decl(const environment& env, const string& name,
>   	     size_t size_in_bits, size_t align_in_bits,
>   	     bool is_struct, const location& locus,
>   	     visibility vis, base_specs& bases,
>   	     member_types& mbrs, data_members& data_mbrs,
>   	     member_functions& member_fns);
>   
> -  class_decl(const environment* env, const string& name,
> +  class_decl(const environment& env, const string& name,
>   	     size_t size_in_bits, size_t align_in_bits,
>   	     bool is_struct, const location& locus,
>   	     visibility vis, base_specs& bases,
>   	     member_types& mbrs, data_members& data_mbrs,
>   	     member_functions& member_fns, bool is_anonymous);
>   
> -  class_decl(const environment* env, const string& name,
> +  class_decl(const environment& env, const string& name,
>   	     size_t size_in_bits, size_t align_in_bits,
>   	     bool is_struct, const location& locus, visibility vis);
>   
> -  class_decl(const environment* env, const string& name,
> +  class_decl(const environment& env, const string& name,
>   	     size_t size_in_bits, size_t align_in_bits,
>   	     bool is_struct, const location& locus,
>   	     visibility vis, bool is_anonymous);
>   
> -  class_decl(const environment* env, const string& name, bool is_struct,
> +  class_decl(const environment& env, const string& name, bool is_struct,
>   	     bool is_declaration_only = true);
>   
>     virtual string
> @@ -4376,26 +4344,26 @@ class union_decl : public class_or_union
>   
>   public:
>   
> -  union_decl(const environment* env, const string& name,
> +  union_decl(const environment& env, const string& name,
>   	     size_t size_in_bits, const location& locus,
>   	     visibility vis, member_types& mbrs,
>   	     data_members& data_mbrs, member_functions& member_fns);
>   
> -  union_decl(const environment* env, const string& name,
> +  union_decl(const environment& env, const string& name,
>   	     size_t size_in_bits, const location& locus,
>   	     visibility vis, member_types& mbrs,
>   	     data_members& data_mbrs, member_functions& member_fns,
>   	     bool is_anonymous);
>   
> -  union_decl(const environment* env, const string& name,
> +  union_decl(const environment& env, const string& name,
>   	     size_t size_in_bits, const location& locus,
>   	     visibility vis);
>   
> -  union_decl(const environment* env, const string& name,
> +  union_decl(const environment& env, const string& name,
>   	     size_t size_in_bits, const location& locus,
>   	     visibility vis, bool is_anonymous);
>   
> -  union_decl(const environment* env, const string& name,
> +  union_decl(const environment& env, const string& name,
>   	     bool is_declaration_only = true);
>   
>     virtual string
> diff --git a/include/abg-reader.h b/include/abg-reader.h
> index 624311bc..d89c6458 100644
> --- a/include/abg-reader.h
> +++ b/include/abg-reader.h
> @@ -17,86 +17,72 @@
>   #include <istream>
>   #include "abg-corpus.h"
>   #include "abg-suppression.h"
> +#include "abg-fe-iface.h"
>   
>   namespace abigail
>   {
>   
> -namespace xml_reader
> +namespace abixml_reader
>   {
>   
>   using namespace abigail::ir;
>   
> -class read_context;
> -
>   translation_unit_sptr
>   read_translation_unit_from_file(const std::string&	file_path,
> -				environment*		env);
> +				environment&		env);
>   
>   translation_unit_sptr
>   read_translation_unit_from_buffer(const std::string&	file_path,
> -				  environment*		env);
> +				  environment&		env);
>   
>   translation_unit_sptr
>   read_translation_unit_from_istream(std::istream*	in,
> -				   environment*	env);
> +				   environment&	env);
>   
>   translation_unit_sptr
> -read_translation_unit(read_context&);
> -
> -/// A convenience typedef for a shared pointer to read_context.
> -typedef shared_ptr<read_context> read_context_sptr;
> +read_translation_unit(fe_iface&);
>   
> -read_context_sptr
> -create_native_xml_read_context(const string& path, environment *env);
> + abigail::fe_iface_sptr
> +create_abixml_reader(const string& path, environment& env);
>   
> -read_context_sptr
> -create_native_xml_read_context(std::istream* in, environment* env);
> -
> -const string&
> -read_context_get_path(const read_context&);
> +fe_iface_sptr
> +create_abixml_reader(std::istream* in, environment& env);
>   
>   corpus_sptr
> -read_corpus_from_native_xml(std::istream* in,
> -			    environment*  env);
> +read_corpus_from_abixml(std::istream* in,
> +			environment&  env);
>   
>   corpus_sptr
> -read_corpus_from_native_xml_file(const string& path,
> -				 environment*  env);
> -
> -corpus_sptr
> -read_corpus_from_input(read_context& ctxt);
> +read_corpus_from_abixml_file(const string& path,
> +			     environment&  env);
>   
>   corpus_group_sptr
> -read_corpus_group_from_input(read_context& ctxt);
> +read_corpus_group_from_input(fe_iface& ctxt);
>   
>   corpus_group_sptr
> -read_corpus_group_from_native_xml(std::istream* in,
> -				  environment*  env);
> +read_corpus_group_from_abixml(std::istream* in,
> +			      environment&  env);
>   
>   corpus_group_sptr
> -read_corpus_group_from_native_xml_file(const string& path,
> -				       environment*  env);
> -
> -void
> -add_read_context_suppressions(read_context& ctxt,
> -			      const suppr::suppressions_type& supprs);
> +read_corpus_group_from_abixml_file(const string& path,
> +				   environment&  env);
>   
>   void
> -consider_types_not_reachable_from_public_interfaces(read_context& ctxt,
> +consider_types_not_reachable_from_public_interfaces(fe_iface& ctxt,
>   						    bool flag);
>   
>   #ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
>   vector<type_base_sptr>*
> -get_types_from_type_id(read_context&, const string&);
> +get_types_from_type_id(fe_iface&, const string&);
>   
>   unordered_map<type_or_decl_base*, vector<type_or_decl_base*>>*
> -get_artifact_used_by_relation_map(read_context&);
> +get_artifact_used_by_relation_map(fe_iface&);
>   #endif
> -}//end xml_reader
> +}//end abixml_reader
>   
>   #ifdef WITH_DEBUG_SELF_COMPARISON
>   bool
> -load_canonical_type_ids(xml_reader::read_context& ctxt,
> +load_canonical_type_ids(fe_iface& ctxt,
>   			const string& file_path);
>   #endif
>   }//end namespace abigail
> diff --git a/include/abg-suppression.h b/include/abg-suppression.h
> index 609fba75..90575f73 100644
> --- a/include/abg-suppression.h
> +++ b/include/abg-suppression.h
> @@ -16,6 +16,8 @@
>   namespace abigail
>   {
>   
> +class fe_iface;
> +
>   /// @brief an engine to suppress the parts of the result of comparing
>   /// two sets of ABI artifacts.
>   ///
> @@ -116,6 +118,12 @@ public:
>   					 const suppression_base& suppr);
>   }; // end class suppression_base
>   
> +/// Convenience typedef for a shared pointer to a @ref suppression.
> +typedef shared_ptr<suppression_base> suppression_sptr;
> +
> +/// Convenience typedef for a vector of @ref suppression_sptr
> +typedef vector<suppression_sptr> suppressions_type;
> +
>   void
>   read_suppressions(std::istream& input,
>   		  suppressions_type& suppressions);
> @@ -821,8 +829,67 @@ is_private_type_suppr_spec(const type_suppression&);
>   
>   bool
>   is_private_type_suppr_spec(const suppression_sptr& s);
> +
> +bool
> +suppression_can_match(const fe_iface&,
> +		      const suppression_base&);
> +
> +bool
> +suppression_matches_function_name(const fe_iface&,
> +				  const suppr::function_suppression&,
> +				  const string&);
> +
> +bool
> +suppression_matches_function_sym_name(const fe_iface&,
> +				      const suppr::function_suppression& s,
> +				      const string& fn_linkage_name);
> +
> +bool
> +suppression_matches_variable_name(const fe_iface&,
> +				  const suppr::variable_suppression& s,
> +				  const string& var_name);
> +
> +bool
> +suppression_matches_variable_sym_name(const fe_iface&,
> +				      const suppr::variable_suppression&,
> +				      const string&);
> +
> +bool
> +suppression_matches_type_name_or_location(const fe_iface&,
> +					  const suppr::type_suppression&,
> +					  const string&,
> +					  const location&);
> +
> +bool
> +is_elf_symbol_suppressed(const fe_iface&,
> +			 const elf_symbol_sptr& symbol);
> +
> +bool
> +is_elf_symbol_suppressed(const fe_iface&,
> +			 const string& sym_name,
> +			 elf_symbol::type sym_type);
> +
> +bool
> +is_function_suppressed(const fe_iface&	fe,
> +		       const string&		fn_name,
> +		       const string&		fn_linkage_name,
> +		       bool			require_drop_property = false);
> +
> +bool
> +is_variable_suppressed(const fe_iface&	fe,
> +		       const string&	var_name,
> +		       const string&	var_linkage_name,
> +		       bool			require_drop_property = false);
> +
> +bool
> +is_type_suppressed(const fe_iface&	fe,
> +		   const string&	type_name,
> +		   const location&	type_location,
> +		   bool&		type_is_private,
> +		   bool			require_drop_property = false);
>   } // end namespace suppr
>   
> +
>   } // end namespace abigail
>   
>   #endif //__ABG_SUPPRESSION_H__
> diff --git a/include/abg-tools-utils.h b/include/abg-tools-utils.h
> index 27bbfefe..9dc9b8d3 100644
> --- a/include/abg-tools-utils.h
> +++ b/include/abg-tools-utils.h
> @@ -15,6 +15,7 @@
>   #include <set>
>   #include <string>
>   #include "abg-suppression.h"
> +#include "abg-elf-based-reader.h"
>   
>   namespace abigail
>   {
> @@ -36,6 +37,10 @@ const char* get_anonymous_enum_internal_name_prefix();
>   
>   bool file_exists(const string&);
>   bool is_regular_file(const string&);
> +bool file_has_dwarf_debug_info(const string& elf_file_path,
> +			       const vector<char**>& debug_info_root_paths);
> +bool file_has_ctf_debug_info(const string& elf_file_path,
> +			     const vector<char**>& debug_info_root_paths);
>   bool is_dir(const string&);
>   bool dir_exists(const string&);
>   bool dir_is_empty(const string &);
> @@ -311,8 +316,14 @@ build_corpus_group_from_kernel_dist_under(const string&	root,
>   					  vector<string>&	kabi_wl_paths,
>   					  suppr::suppressions_type&	supprs,
>   					  bool				verbose,
> -					  environment_sptr&		env,
> +					  environment&			env,
>   					  corpus::origin	origin = corpus::DWARF_ORIGIN);
> +
> +elf_based_reader_sptr
> +create_best_elf_based_reader(const string& elf_file_path,
> +			     const vector<char**>& debug_info_root_paths,
> +			     environment& env);
> +
>   }// end namespace tools_utils
>   
>   /// A macro that expands to aborting the program when executed.
> diff --git a/include/abg-writer.h b/include/abg-writer.h
> index ab01b486..58f60b74 100644
> --- a/include/abg-writer.h
> +++ b/include/abg-writer.h
> @@ -36,7 +36,7 @@ class write_context;
>   typedef shared_ptr<write_context> write_context_sptr;
>   
>   write_context_sptr
> -create_write_context(const environment *env,
> +create_write_context(const environment& env,
>   		     ostream& output_stream);
>   
>   void
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 1748f0b8..70cc04a5 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -26,8 +26,10 @@ abg-suppression-priv.h			\
>   abg-suppression.cc			\
>   abg-comp-filter.cc			\
>   abg-reader.cc				\
> -abg-elf-reader-common.cc		\
>   abg-dwarf-reader.cc			\
> +abg-fe-iface.cc				\
> +abg-elf-based-reader.cc			\
> +abg-elf-reader.cc			\
>   abg-libxml-utils.cc			\
>   abg-hash.cc				\
>   abg-writer.cc				\
> diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc
> index 6e3b2b55..0868d384 100644
> --- a/src/abg-comparison.cc
> +++ b/src/abg-comparison.cc
> @@ -3133,8 +3133,6 @@ compute_diff(const decl_base_sptr	first,
>     if (!first || !second)
>       return diff_sptr();
>   
> -  ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     diff_sptr d;
>     if (is_type(first) && is_type(second))
>       d = compute_diff_for_types(first, second, ctxt);
> @@ -3165,9 +3163,6 @@ compute_diff(const type_base_sptr	first,
>     decl_base_sptr f = get_type_declaration(first),
>       s = get_type_declaration(second);
>   
> -  if (first && second)
> -    ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     diff_sptr d = compute_diff_for_types(f,s, ctxt);
>     ABG_ASSERT(d);
>     return d;
> @@ -3317,9 +3312,6 @@ compute_diff(const var_decl_sptr	first,
>   	     const var_decl_sptr	second,
>   	     diff_context_sptr		ctxt)
>   {
> -  if (first && second)
> -    ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
>     ctxt->initialize_canonical_diff(d);
>   
> @@ -3451,9 +3443,6 @@ compute_diff(pointer_type_def_sptr	first,
>   	     pointer_type_def_sptr	second,
>   	     diff_context_sptr		ctxt)
>   {
> -  if (first && second)
> -    ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
>   				       second->get_pointed_to_type(),
>   				       ctxt);
> @@ -3607,9 +3596,6 @@ compute_diff(array_type_def_sptr	first,
>   	     array_type_def_sptr	second,
>   	     diff_context_sptr		ctxt)
>   {
> -  if (first && second)
> -    ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     diff_sptr d = compute_diff_for_types(first->get_element_type(),
>   				       second->get_element_type(),
>   				       ctxt);
> @@ -3742,9 +3728,6 @@ compute_diff(reference_type_def_sptr	first,
>   	     reference_type_def_sptr	second,
>   	     diff_context_sptr		ctxt)
>   {
> -  if (first && second)
> -    ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
>   				       second->get_pointed_to_type(),
>   				       ctxt);
> @@ -3892,9 +3875,6 @@ compute_diff(const qualified_type_def_sptr	first,
>   	     const qualified_type_def_sptr	second,
>   	     diff_context_sptr			ctxt)
>   {
> -  if (first && second)
> -    ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
>   				       second->get_underlying_type(),
>   				       ctxt);
> @@ -4110,9 +4090,6 @@ compute_diff(const enum_type_decl_sptr first,
>   	     const enum_type_decl_sptr second,
>   	     diff_context_sptr ctxt)
>   {
> -  if (first && second)
> -    ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
>   					second->get_underlying_type(),
>   					ctxt);
> @@ -5596,9 +5573,6 @@ compute_diff(const class_decl_sptr	first,
>   	     const class_decl_sptr	second,
>   	     diff_context_sptr		ctxt)
>   {
> -  if (first && second)
> -    ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     class_decl_sptr f = is_class_type(look_through_decl_only_class(first)),
>       s = is_class_type(look_through_decl_only_class(second));
>   
> @@ -5821,15 +5795,6 @@ compute_diff(const class_decl::base_spec_sptr	first,
>   	     const class_decl::base_spec_sptr	second,
>   	     diff_context_sptr			ctxt)
>   {
> -  if (first && second)
> -    {
> -      ABG_ASSERT(first->get_environment() == second->get_environment());
> -      ABG_ASSERT(first->get_base_class()->get_environment()
> -	     == second->get_base_class()->get_environment());
> -      ABG_ASSERT(first->get_environment()
> -	     == first->get_base_class()->get_environment());
> -    }
> -
>     class_diff_sptr cl = compute_diff(first->get_base_class(),
>   				    second->get_base_class(),
>   				    ctxt);
> @@ -5945,9 +5910,6 @@ compute_diff(const union_decl_sptr	first,
>   	     const union_decl_sptr	second,
>   	     diff_context_sptr	ctxt)
>   {
> -  if (first && second)
> -    ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     union_diff_sptr changes(new union_diff(first, second, ctxt));
>   
>     ctxt->initialize_canonical_diff(changes);
> @@ -6449,9 +6411,6 @@ compute_diff(const scope_decl_sptr	first,
>   {
>     ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
>   
> -  if (first && second)
> -    ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     compute_diff(first->get_member_decls().begin(),
>   	       first->get_member_decls().end(),
>   	       second->get_member_decls().begin(),
> @@ -6482,10 +6441,6 @@ compute_diff(const scope_decl_sptr	first_scope,
>   	     const scope_decl_sptr	second_scope,
>   	     diff_context_sptr		ctxt)
>   {
> -  if (first_scope && second_scope)
> -    ABG_ASSERT(first_scope->get_environment()
> -	   == second_scope->get_environment());
> -
>     scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
>     d = compute_diff(first_scope, second_scope, d, ctxt);
>     ctxt->initialize_canonical_diff(d);
> @@ -6632,8 +6587,6 @@ compute_diff(const function_decl::parameter_sptr	first,
>     if (!first || !second)
>       return fn_parm_diff_sptr();
>   
> -  ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
>     ctxt->initialize_canonical_diff(result);
>   
> @@ -6930,8 +6883,6 @@ compute_diff(const function_type_sptr	first,
>         return function_type_diff_sptr();
>       }
>   
> -  ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
>   
>     diff_utils::compute_diff(first->get_first_parm(),
> @@ -7072,8 +7023,6 @@ compute_diff(const function_decl_sptr first,
>         return function_decl_diff_sptr();
>       }
>   
> -  ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     function_type_diff_sptr type_diff = compute_diff(first->get_type(),
>   						   second->get_type(),
>   						   ctxt);
> @@ -7196,9 +7145,6 @@ compute_diff(const type_decl_sptr	first,
>   	     const type_decl_sptr	second,
>   	     diff_context_sptr		ctxt)
>   {
> -  if (first && second)
> -    ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
>   
>     // We don't need to actually compute a diff here as a type_decl
> @@ -7349,9 +7295,6 @@ compute_diff(const typedef_decl_sptr	first,
>   	     const typedef_decl_sptr	second,
>   	     diff_context_sptr		ctxt)
>   {
> -  if (first && second)
> -    ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
>   				       second->get_underlying_type(),
>   				       ctxt);
> @@ -7470,8 +7413,6 @@ compute_diff(const translation_unit_sptr	first,
>   {
>     ABG_ASSERT(first && second);
>   
> -  ABG_ASSERT(first->get_environment() == second->get_environment());
> -
>     if (!ctxt)
>       ctxt.reset(new diff_context);
>   
> @@ -10929,10 +10870,6 @@ compute_diff(const corpus_sptr	f,
>   
>     ABG_ASSERT(f && s);
>   
> -  // We can only compare two corpora that were built out of the same
> -  // environment.
> -  ABG_ASSERT(f->get_environment() == s->get_environment());
> -
>     if (!ctxt)
>       ctxt.reset(new diff_context);
>   
> @@ -12272,11 +12209,11 @@ is_diff_of_variadic_parameter_type(const diff* d)
>       return false;
>   
>     type_base_sptr t = is_type(d->first_subject());
> -  if (t && t->get_environment()->is_variadic_parameter_type(t))
> +  if (t && t->get_environment().is_variadic_parameter_type(t))
>       return true;
>   
>     t = is_type(d->second_subject());
> -  if (t && t->get_environment()->is_variadic_parameter_type(t))
> +  if (t && t->get_environment().is_variadic_parameter_type(t))
>       return true;
>   
>     return false;
> diff --git a/src/abg-corpus-priv.h b/src/abg-corpus-priv.h
> index 8719be56..0b40d800 100644
> --- a/src/abg-corpus-priv.h
> +++ b/src/abg-corpus-priv.h
> @@ -403,12 +403,12 @@ public:
>     ///
>     /// @param fn the function to add to the set of exported functions.
>     void
> -  add_fn_to_exported(function_decl* fn)
> +  add_fn_to_exported(const function_decl* fn)
>     {
>       if (!fn_is_in_id_fns_map(fn))
>         {
> -	fns_.push_back(fn);
> -	add_fn_to_id_fns_map(fn);
> +	fns_.push_back(const_cast<function_decl*>(fn));
> +	add_fn_to_id_fns_map(const_cast<function_decl*>(fn));
>         }
>     }
>   
> @@ -416,13 +416,13 @@ public:
>     ///
>     /// @param fn the variable to add to the set of exported variables.
>     void
> -  add_var_to_exported(var_decl* var)
> +  add_var_to_exported(const var_decl* var)
>     {
>       const string& id = get_id(*var);
>       if (!var_id_is_in_id_var_map(id))
>         {
> -	vars_.push_back(var);
> -	add_var_to_map(var);
> +	vars_.push_back(const_cast<var_decl*>(var));
> +	add_var_to_map(const_cast<var_decl*>(var));
>         }
>     }
>   
> @@ -667,7 +667,7 @@ struct corpus::priv
>     mutable unordered_map<string, type_base_sptr> canonical_types_;
>     string					format_major_version_number_;
>     string					format_minor_version_number_;
> -  environment*					env;
> +  const environment&				env;
>     corpus_group*				group;
>     corpus::exported_decls_builder_sptr		exported_decls_builder;
>     corpus::origin				origin_;
> @@ -717,8 +717,8 @@ private:
>     mutable abg_compat::optional<elf_symbols> unrefed_fun_symbols;
>   
>   public:
> -  priv(const string &	p,
> -       environment*	e)
> +  priv(const string &		p,
> +       const environment&	e)
>       : env(e),
>         group(),
>         origin_(ARTIFICIAL_ORIGIN),
> diff --git a/src/abg-corpus.cc b/src/abg-corpus.cc
> index 0b23667f..8c1e6158 100644
> --- a/src/abg-corpus.cc
> +++ b/src/abg-corpus.cc
> @@ -133,7 +133,7 @@ corpus::exported_decls_builder::exported_variables()
>   ///
>   /// @param fn the function to add the set of exported functions.
>   void
> -corpus::exported_decls_builder::maybe_add_fn_to_exported_fns(function_decl* fn)
> +corpus::exported_decls_builder::maybe_add_fn_to_exported_fns(const function_decl* fn)
>   {
>     if (!fn->get_is_in_public_symbol_table())
>       return;
> @@ -156,7 +156,7 @@ corpus::exported_decls_builder::maybe_add_fn_to_exported_fns(function_decl* fn)
>   ///
>   /// @param fn the variable to add the set of exported variables.
>   void
> -corpus::exported_decls_builder::maybe_add_var_to_exported_vars(var_decl* var)
> +corpus::exported_decls_builder::maybe_add_var_to_exported_vars(const var_decl* var)
>   {
>     if (!var->get_is_in_public_symbol_table())
>       return;
> @@ -596,7 +596,7 @@ corpus::priv::~priv()
>   /// @param env the environment of the corpus.
>   ///
>   /// @param path the path to the file containing the ABI corpus.
> -corpus::corpus(ir::environment* env, const string& path)
> +corpus::corpus(const ir::environment& env, const string& path)
>   {
>     priv_.reset(new priv(path, env));
>     init_format_version();
> @@ -607,31 +607,11 @@ corpus::~corpus() = default;
>   /// Getter of the enviroment of the corpus.
>   ///
>   /// @return the environment of this corpus.
> -const environment*
> +const environment&
>   corpus::get_environment() const
>   {return priv_->env;}
>   
> -/// Getter of the enviroment of the corpus.
> -///
> -/// @return the environment of this corpus.
> -environment*
> -corpus::get_environment()
> -{return priv_->env;}
> -
> -/// Setter of the environment of this corpus.
> -///
> -/// @param e the new environment.
> -void
> -corpus::set_environment(environment* e)
> -{
> -  priv_->env = e;
> -  init_format_version();
> -}
> -
> -/// Add a translation unit to the current ABI Corpus. Next time
> -/// corpus::save is called, all the translation unit that got added to
> -/// the corpus are going to be serialized on disk in the file
> -/// associated to the current corpus.
> +/// Add a translation unit to the current ABI Corpus.
>   ///
>   /// Note that two translation units with the same path (as returned by
>   /// translation_unit::get_path) cannot be added to the same @ref
> @@ -639,13 +619,8 @@ corpus::set_environment(environment* e)
>   ///
>   /// @param tu the new translation unit to add.
>   void
> -corpus::add(const translation_unit_sptr tu)
> +corpus::add(const translation_unit_sptr& tu)
>   {
> -  if (!tu->get_environment())
> -    tu->set_environment(get_environment());
> -
> -  ABG_ASSERT(tu->get_environment() == get_environment());
> -
>     ABG_ASSERT(priv_->members.insert(tu).second);
>   
>     if (!tu->get_absolute_path().empty())
> @@ -741,7 +716,7 @@ void
>   corpus::record_type_as_reachable_from_public_interfaces(const type_base& t)
>   {
>     string repr = get_pretty_representation(&t, /*internal=*/true);
> -  interned_string s = t.get_environment()->intern(repr);
> +  interned_string s = t.get_environment().intern(repr);
>     priv_->get_public_types_pretty_representations()->insert(s);
>   }
>   
> @@ -759,7 +734,7 @@ bool
>   corpus::type_is_reachable_from_public_interfaces(const type_base& t) const
>   {
>     string repr = get_pretty_representation(&t, /*internal=*/true);
> -  interned_string s = t.get_environment()->intern(repr);
> +  interned_string s = t.get_environment().intern(repr);
>   
>     return (priv_->get_public_types_pretty_representations()->find(s)
>   	  !=  priv_->get_public_types_pretty_representations()->end());
> @@ -839,13 +814,10 @@ corpus::set_group(corpus_group* g)
>   void
>   corpus::init_format_version()
>   {
> -  if (priv_->env)
> -    {
> -      set_format_major_version_number
> -	(priv_->env->get_config().get_format_major_version_number());
> -      set_format_minor_version_number
> -	(priv_->env->get_config().get_format_minor_version_number());
> -    }
> +  set_format_major_version_number
> +    (priv_->env.get_config().get_format_major_version_number());
> +  set_format_minor_version_number
> +    (priv_->env.get_config().get_format_minor_version_number());
>   }
>   
>   /// Getter for the origin of the corpus.
> @@ -1013,7 +985,9 @@ corpus::is_empty() const
>     return (members_empty
>   	  && (!get_symtab() || !get_symtab()->has_symbols())
>   	  && priv_->soname.empty()
> -	  && priv_->needed.empty());
> +	  && priv_->needed.empty()
> +	  && priv_->architecture_name.empty()
> +	  && !priv_->group);
>   }
>   
>   /// Compare the current @ref corpus against another one.
> @@ -1690,8 +1664,12 @@ struct corpus_group::priv
>     }
>   }; // end corpus_group::priv
>   
> -/// Default constructor of the @ref corpus_group type.
> -corpus_group::corpus_group(environment* env, const string& path = "")
> +/// Constructor of the @ref corpus_group type.
> +///
> +/// @param env the environment of the @ref corpus_group.
> +///
> +/// @param path the path to the file represented by the corpus group.
> +corpus_group::corpus_group(const environment& env, const string& path = "")
>     : corpus(env, path), priv_(new priv)
>   {}
>   
> @@ -1708,15 +1686,6 @@ corpus_group::add_corpus(const corpus_sptr& corp)
>     if (!corp)
>       return;
>   
> -  // Ensure the new environment patches the current one.
> -  if (const environment* cur_env = get_environment())
> -    {
> -      if (environment* corp_env = corp->get_environment())
> -	ABG_ASSERT(cur_env == corp_env);
> -    }
> -  else
> -    set_environment(corp->get_environment());
> -
>     // Ensure the new architecture name matches the current one.
>     string cur_arch = get_architecture_name(),
>       corp_arch = corp->get_architecture_name();
> diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc
> index e307fcd7..cabb919e 100644
> --- a/src/abg-ctf-reader.cc
> +++ b/src/abg-ctf-reader.cc
> @@ -23,17 +23,18 @@
>   
>   #include "abg-internal.h"
>   #include "abg-ir-priv.h"
> -#include "abg-elf-helpers.h"
> +#include "abg-symtab-reader.h"
>   
> +
> +#include "abg-internal.h"
>   // <headers defining libabigail's API go under here>
>   ABG_BEGIN_EXPORT_DECLARATIONS
>   
>   #include "abg-ctf-reader.h"
> -#include "abg-libxml-utils.h"
> -#include "abg-reader.h"
> +#include "abg-elf-based-reader.h"
>   #include "abg-corpus.h"
> -#include "abg-symtab-reader.h"
>   #include "abg-tools-utils.h"
> +#include "abg-elf-helpers.h"
>   
>   ABG_END_EXPORT_DECLARATIONS
>   // </headers defining libabigail's API>
> @@ -46,16 +47,104 @@ using std::dynamic_pointer_cast;
>   using abigail::tools_utils::dir_name;
>   using abigail::tools_utils::file_exists;
>   
> -class read_context
> -{
> -public:
> -  /// The name of the ELF file from which the CTF archive got
> -  /// extracted.
> -  string filename;
> +class reader;
> +
> +static typedef_decl_sptr
> +process_ctf_typedef(reader *rdr,
> +                    corpus_sptr corp,
> +                    translation_unit_sptr tunit,
> +                    ctf_dict_t *ctf_dictionary,
> +                    ctf_id_t ctf_type);
> +
> +static type_decl_sptr
> +process_ctf_base_type(reader *rdr,
> +                      corpus_sptr corp,
> +                      translation_unit_sptr tunit,
> +                      ctf_dict_t *ctf_dictionary,
> +                      ctf_id_t ctf_type);
> +
> +static decl_base_sptr
> +build_ir_node_for_variadic_parameter_type(reader &rdr,
> +                                          translation_unit_sptr tunit);
> +
> +static function_type_sptr
> +process_ctf_function_type(reader *rdr,
> +                          corpus_sptr corp,
> +                          translation_unit_sptr tunit,
> +                          ctf_dict_t *ctf_dictionary,
> +                          ctf_id_t ctf_type);
> +
> +static void
> +process_ctf_sou_members(reader *rdr,
> +                        corpus_sptr corp,
> +                        translation_unit_sptr tunit,
> +                        ctf_dict_t *ctf_dictionary,
> +                        ctf_id_t ctf_type,
> +                        class_or_union_sptr sou);
> +
> +static type_base_sptr
> +process_ctf_forward_type(reader *rdr,
> +                         translation_unit_sptr tunit,
> +                         ctf_dict_t *ctf_dictionary,
> +                         ctf_id_t ctf_type);
> +
> +static class_decl_sptr
> +process_ctf_struct_type(reader *rdr,
> +                        corpus_sptr corp,
> +                        translation_unit_sptr tunit,
> +                        ctf_dict_t *ctf_dictionary,
> +                        ctf_id_t ctf_type);
> +
> +static union_decl_sptr
> +process_ctf_union_type(reader *rdr,
> +                       corpus_sptr corp,
> +                       translation_unit_sptr tunit,
> +                       ctf_dict_t *ctf_dictionary,
> +                       ctf_id_t ctf_type);
> +
> +static array_type_def_sptr
> +process_ctf_array_type(reader *rdr,
> +                       corpus_sptr corp,
> +                       translation_unit_sptr tunit,
> +                       ctf_dict_t *ctf_dictionary,
> +                       ctf_id_t ctf_type);
> +
> +static type_base_sptr
> +process_ctf_qualified_type(reader *rdr,
> +                           corpus_sptr corp,
> +                           translation_unit_sptr tunit,
> +                           ctf_dict_t *ctf_dictionary,
> +                           ctf_id_t ctf_type);
> +
> +static pointer_type_def_sptr
> +process_ctf_pointer_type(reader *rdr,
> +                         corpus_sptr corp,
> +                         translation_unit_sptr tunit,
> +                         ctf_dict_t *ctf_dictionary,
> +                         ctf_id_t ctf_type);
> +
> +static enum_type_decl_sptr
> +process_ctf_enum_type(reader *rdr,
> +                      translation_unit_sptr tunit,
> +                      ctf_dict_t *ctf_dictionary,
> +                      ctf_id_t ctf_type);
>   
> -  /// The IR environment.
> -  ir::environment *ir_env;
> +static void
> +fill_ctf_section(const Elf_Scn *elf_section, ctf_sect_t *ctf_section);
>   
> +static ctf_id_t
> +lookup_symbol_in_ctf_archive(ctf_archive_t *ctfa, ctf_dict_t **ctf_dict,
> +                             const char *sym_name);
> +
> +static std::string
> +dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type);
> +
> +/// The abstraction of a CTF reader.
> +///
> +/// It groks the type information contains the CTF-specific part of
> +/// the ELF file and builds an ABI corpus out of it.
> +class reader : public elf_based_reader
> +{
>     /// The CTF archive read from FILENAME.  If an archive couldn't
>     /// be read from the file then this is NULL.
>     ctf_archive_t *ctfa;
> @@ -67,140 +156,20 @@ public:
>     /// A set associating unknown CTF type ids
>     std::set<ctf_id_t> unknown_types_set;
>   
> -  /// libelf handler for the ELF file from which we read the CTF data,
> -  /// and the corresponding file descriptor.
> -  Elf *elf_handler;
> -  int elf_fd;
> -
> -  /// libelf handler for the ELF file from which we read the CTF data,
> -  /// and the corresponding file descriptor found in external .debug file
> -  Elf *elf_handler_dbg;
> -  int elf_fd_dbg;
> -
> -  /// The symtab read from the ELF file.
> -  symtab_reader::symtab_sptr symtab;
> -
>     /// Raw contents of several sections from the ELF file.  These are
>     /// used by libctf.
>     ctf_sect_t ctf_sect;
>     ctf_sect_t symtab_sect;
>     ctf_sect_t strtab_sect;
>   
> -  corpus_sptr			cur_corpus_;
> -  corpus_group_sptr		cur_corpus_group_;
> -  corpus::exported_decls_builder* exported_decls_builder_;
> -  // The set of directories under which to look for debug info.
> -  vector<char**>		debug_info_root_paths_;
> -
> -  /// Setter of the exported decls builder object.
> -  ///
> -  /// Note that this @ref read_context is not responsible for the live
> -  /// time of the exported_decls_builder object.  The corpus is.
> -  ///
> -  /// @param b the new builder.
> -  void
> -  exported_decls_builder(corpus::exported_decls_builder* b)
> -  {exported_decls_builder_ = b;}
> +public:
>   
>     /// Getter of the exported decls builder object.
>     ///
>     /// @return the exported decls builder.
>     corpus::exported_decls_builder*
>     exported_decls_builder()
> -  {return exported_decls_builder_;}
> -
> -  /// If a given function decl is suitable for the set of exported
> -  /// functions of the current corpus, this function adds it to that
> -  /// set.
> -  ///
> -  /// @param fn the function to consider for inclusion into the set of
> -  /// exported functions of the current corpus.
> -  void
> -  maybe_add_fn_to_exported_decls(function_decl* fn)
> -  {
> -    if (fn)
> -      if (corpus::exported_decls_builder* b = exported_decls_builder())
> -	b->maybe_add_fn_to_exported_fns(fn);
> -  }
> -
> -  /// If a given variable decl is suitable for the set of exported
> -  /// variables of the current corpus, this variable adds it to that
> -  /// set.
> -  ///
> -  /// @param fn the variable to consider for inclusion into the set of
> -  /// exported variables of the current corpus.
> -  void
> -  maybe_add_var_to_exported_decls(var_decl* var)
> -  {
> -    if (var)
> -      if (corpus::exported_decls_builder* b = exported_decls_builder())
> -	b->maybe_add_var_to_exported_vars(var);
> -  }
> -
> -  /// Getter of the current corpus group being constructed.
> -  ///
> -  /// @return current the current corpus being constructed, if any, or
> -  /// nil.
> -  const corpus_group_sptr
> -  current_corpus_group() const
> -  {return cur_corpus_group_;}
> -
> -  /// Test if there is a corpus group being built.
> -  ///
> -  /// @return if there is a corpus group being built, false otherwise.
> -  bool
> -  has_corpus_group() const
> -  {return bool(cur_corpus_group_);}
> -
> -  /// Return the main corpus from the current corpus group, if any.
> -  ///
> -  /// @return the main corpus of the current corpus group, if any, nil
> -  /// if no corpus group is being constructed.
> -  corpus_sptr
> -  main_corpus_from_current_group()
> -  {
> -    if (cur_corpus_group_)
> -      return cur_corpus_group_->get_main_corpus();
> -    return corpus_sptr();
> -  }
> -
> -  /// Test if the current corpus being built is the main corpus of the
> -  /// current corpus group.
> -  ///
> -  /// @return return true iff the current corpus being built is the
> -  /// main corpus of the current corpus group.
> -  bool
> -  current_corpus_is_main_corpus_from_current_group()
> -  {
> -    corpus_sptr main_corpus = main_corpus_from_current_group();
> -
> -    if (main_corpus && main_corpus.get() == cur_corpus_.get())
> -      return true;
> -
> -    return false;
> -  }
> -
> -  /// Return true if the current corpus is part of a corpus group
> -  /// being built and if it's not the main corpus of the group.
> -  ///
> -  /// For instance, this would return true if we are loading a linux
> -  /// kernel *module* that is part of the current corpus group that is
> -  /// being built.  In this case, it means we should re-use types
> -  /// coming from the "vmlinux" binary that is the main corpus of the
> -  /// group.
> -  ///
> -  /// @return the corpus group the current corpus belongs to, if the
> -  /// current corpus is part of a corpus group being built. Nil otherwise.
> -  corpus_sptr
> -  should_reuse_type_from_corpus_group()
> -  {
> -    if (has_corpus_group())
> -      if (corpus_sptr main_corpus = main_corpus_from_current_group())
> -	if (!current_corpus_is_main_corpus_from_current_group())
> -	  return current_corpus_group();
> -
> -    return corpus_sptr();
> -  }
> +  {return corpus()->get_exported_decls_builder().get();}
>   
>     /// Associate a given CTF type ID with a given libabigail IR type.
>     ///
> @@ -269,67 +238,490 @@ public:
>     /// the types and declarations that are to be created later.  Note
>     /// that ABI artifacts that are to be compared all need to be
>     /// created within the same environment.
> -  read_context(const string& elf_path,
> -               const vector<char**>& debug_info_root_paths,
> -               ir::environment *env) :
> -   ctfa(NULL)
> +  reader(const string&		elf_path,
> +	 const vector<char**>&	debug_info_root_paths,
> +	 environment&		env)
> +    : elf_based_reader(elf_path, debug_info_root_paths, env)
>     {
> -    initialize(elf_path, debug_info_root_paths, env);
> +    initialize();
>     }
>   
> -  /// Initializer of read_context.
> +  /// Initializer of the reader.
>     ///
> -  /// @param elf_path the path to the elf file the context is to be
> -  /// used for.
> +  /// This is useful to clear out the data used by the reader and get
> +  /// it ready to be used again.
>     ///
> -  /// @param debug_info_root_paths vector with the paths
> -  /// to directories where .debug file is located.
> +  /// Note that the reader eeps the same environment it has been
> +  /// originally created with.
>     ///
> -  /// @param environment the environment used by the current context.
> -  /// This environment contains resources needed by the reader and by
> -  /// the types and declarations that are to be created later.  Note
> -  /// that ABI artifacts that are to be compared all need to be
> -  /// created within the same environment.
> +  /// Please also note that the life time of this environment object
> +  /// must be greater than the life time of the resulting @ref
> +  /// reader the context uses resources that are allocated in
> +  /// the environment.
> +  void
> +  initialize()
> +  {
> +    ctfa = nullptr;
> +    types_map.clear();
> +    corpus_group().reset();
> +  }
> +
> +  /// Initializer of the reader.
> +  ///
> +  ///
> +  /// @param elf_path the new path to the new ELF file to use.
> +  ///
> +  /// @param debug_info_root_paths a vector of paths to use to look
> +  /// for debug info that is split out into a separate file.
> +  ///
> +  /// This is useful to clear out the data used by the reader and get
> +  /// it ready to be used again.
> +  ///
> +  /// Note that the reader eeps the same environment it has been
> +  /// originally created with.
>     ///
>     /// Please also note that the life time of this environment object
>     /// must be greater than the life time of the resulting @ref
> -  /// read_context the context uses resources that are allocated in
> +  /// reader the context uses resources that are allocated in
>     /// the environment.
>     void
>     initialize(const string& elf_path,
> -             const vector<char**>& debug_info_root_paths,
> -             ir::environment *env)
> +             const vector<char**>& debug_info_root_paths)
>     {
> -    types_map.clear();
> -    filename = elf_path;
> -    ir_env = env;
> -    elf_handler = NULL;
> -    elf_handler_dbg = NULL;
> -    elf_fd = -1;
> -    elf_fd_dbg = -1;
> -    symtab.reset();
> -    cur_corpus_group_.reset();
> -    exported_decls_builder_ = 0;
> -    debug_info_root_paths_ = debug_info_root_paths;
> +    reset(elf_path, debug_info_root_paths);
> +  }
> +
> +  /// Getter of the environment of the current CTF reader.
> +  ///
> +  /// @return the environment of the current CTF reader.
> +  const environment&
> +  env() const
> +  {return options().env;}
> +
> +  /// Getter of the environment of the current CTF reader.
> +  ///
> +  /// @return the environment of the current CTF reader.
> +  environment&
> +  env()
> +  {return options().env;}
> +
> +  /// Look for vmlinux.ctfa file in default directory or in
> +  /// directories provided by debug-info-dir command line option,
> +  /// it stores location path in @ref ctfa_file.
> +  ///
> +  /// @param ctfa_file file name found.
> +  /// @return true if file is found.
> +  bool
> +  find_ctfa_file(std::string& ctfa_file)
> +  {
> +    std::string ctfa_dirname;
> +    dir_name(corpus_path(), ctfa_dirname, false);
> +
> +    // In corpus group we assume vmlinux as first file to
> +    // be processed, so default location for vmlinux.cfa
> +    // is vmlinux dirname.
> +    ctfa_file = ctfa_dirname + "/vmlinux.ctfa";
> +    if (file_exists(ctfa_file))
> +      return true;
> +
> +    // If it's proccessing a module, then location directory
> +    // for vmlinux.ctfa should be provided with --debug-info-dir
> +    // option.
> +    for (const auto& path : debug_info_root_paths())
> +      {
> +	ctfa_dirname = *path;
> +	ctfa_file = ctfa_dirname + "/vmlinux.ctfa";
> +	if (file_exists(ctfa_file))
> +	  return true;
> +      }
> +
> +    return false;
> +  }
> +
> +  /// Slurp certain information from the underlying ELF file, and
> +  /// install it the current libabigail corpus associated to the
> +  /// current CTF reader.
> +  ///
> +  /// @param status the resulting status flags.
> +  void
> +  slurp_elf_info(fe_iface::status& status)
> +  {
> +    // Read the ELF-specific parts of the corpus.
> +    elf_reader::reader::read_corpus(status);
> +
> +    if ((status & STATUS_NO_SYMBOLS_FOUND)
> +	|| !(status & STATUS_OK))
> +      // Either we couldn't find ELF symbols or something went badly
> +      // wrong.  There is nothing we can do with this ELF file.  Bail
> +      // out.
> +      return;
> +
> +    corpus_sptr corp = corpus();
> +    if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
> +	&& corpus_group())
> +      {
> +	status |= fe_iface::STATUS_OK;
> +	return;
> +      }
> +
> +    /* Get the raw ELF section contents for libctf.  */
> +    if (!find_ctf_section())
> +      {
> +	status |= fe_iface::STATUS_DEBUG_INFO_NOT_FOUND;
> +	return;
> +      }
> +
> +    GElf_Ehdr *ehdr, eh_mem;
> +    if (!(ehdr = gelf_getehdr(elf_handle(), &eh_mem)))
> +      return;
> +
> +    // ET_{EXEC,DYN} needs .dyn{sym,str} in ctf_arc_bufopen
> +    const char *symtab_name = ".dynsym";
> +    const char *strtab_name = ".dynstr";
> +
> +    if (ehdr->e_type == ET_REL)
> +      {
> +	symtab_name = ".symtab";
> +	strtab_name = ".strtab";
> +      }
> +
> +    const Elf_Scn* ctf_scn = find_ctf_section();
> +    fill_ctf_section(ctf_scn, &ctf_sect);
> +
> +    const Elf_Scn* symtab_scn =
> +      elf_helpers::find_section_by_name(elf_handle(), symtab_name);
> +    fill_ctf_section(symtab_scn, &symtab_sect);
> +
> +    const Elf_Scn* strtab_scn =
> +      elf_helpers::find_section_by_name(elf_handle(), strtab_name);
> +    fill_ctf_section(strtab_scn, &strtab_sect);
> +
> +    status |= fe_iface::STATUS_OK;
> +  }
> +
> +  /// Process a CTF archive and create libabigail IR for the types,
> +  /// variables and function declarations found in the archive, iterating
> +  /// over public symbols.  The IR is added to the given corpus.
> +  ///
> +  /// @param corp the IR corpus to which add the new contents.
> +  void
> +  process_ctf_archive(corpus_sptr corp)
> +  {
> +    /* We only have a translation unit.  */
> +    translation_unit_sptr ir_translation_unit =
> +      std::make_shared<translation_unit>(env(), "", 64);
> +    ir_translation_unit->set_language(translation_unit::LANG_C);
> +    corp->add(ir_translation_unit);
> +
> +    int ctf_err;
> +    ctf_dict_t *ctf_dict, *dict_tmp;
> +    const auto symt = symtab();
> +    symtab_reader::symtab_filter filter = symt->make_filter();
> +    filter.set_public_symbols();
> +    std::string dict_name;
> +
> +    if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
> +	&& corpus_group())
> +      {
> +	tools_utils::base_name(corpus_path(), dict_name);
> +
> +	if (dict_name != "vmlinux")
> +	  // remove .ko suffix
> +	  dict_name.erase(dict_name.length() - 3, 3);
> +
> +	std::replace(dict_name.begin(), dict_name.end(), '-', '_');
> +      }
> +
> +    if ((ctf_dict = ctf_dict_open(ctfa,
> +				  dict_name.empty() ? NULL : dict_name.c_str(),
> +				  &ctf_err)) == NULL)
> +      {
> +	fprintf(stderr, "ERROR dictionary not found\n");
> +	abort();
> +      }
> +
> +    dict_tmp = ctf_dict;
> +
> +    for (const auto& symbol : symtab_reader::filtered_symtab(*symt, filter))
> +      {
> +	std::string sym_name = symbol->get_name();
> +	ctf_id_t ctf_sym_type;
> +
> +	ctf_sym_type = lookup_symbol_in_ctf_archive(ctfa, &ctf_dict,
> +						    sym_name.c_str());
> +	if (ctf_sym_type == CTF_ERR)
> +          continue;
> +
> +	if (ctf_type_kind(ctf_dict, ctf_sym_type) != CTF_K_FUNCTION)
> +	  {
> +	    const char *var_name = sym_name.c_str();
> +	    type_base_sptr var_type = lookup_type(corp, ir_translation_unit,
> +						  ctf_dict, ctf_sym_type);
> +	    if (!var_type)
> +	      /* Ignore variable if its type can't be sorted out.  */
> +	      continue;
> +
> +	    var_decl_sptr var_declaration;
> +	    var_declaration.reset(new var_decl(var_name,
> +					       var_type,
> +					       location(),
> +					       var_name));
> +
> +	    var_declaration->set_symbol(symbol);
> +	    add_decl_to_scope(var_declaration,
> +			      ir_translation_unit->get_global_scope());
> +	    var_declaration->set_is_in_public_symbol_table(true);
> +	    maybe_add_var_to_exported_decls(var_declaration.get());
> +	  }
> +	else
> +	  {
> +	    const char *func_name = sym_name.c_str();
> +	    ctf_id_t ctf_sym = ctf_sym_type;
> +	    type_base_sptr func_type = lookup_type(corp, ir_translation_unit,
> +						   ctf_dict, ctf_sym);
> +	    if (!func_type)
> +	      /* Ignore function if its type can't be sorted out.  */
> +	      continue;
> +
> +	    function_decl_sptr func_declaration;
> +	    func_declaration.reset(new function_decl(func_name,
> +						     func_type,
> +						     0 /* is_inline */,
> +						     location()));
> +	    func_declaration->set_symbol(symbol);
> +	    add_decl_to_scope(func_declaration,
> +			      ir_translation_unit->get_global_scope());
> +	    func_declaration->set_is_in_public_symbol_table(true);
> +	    maybe_add_fn_to_exported_decls(func_declaration.get());
> +	  }
> +
> +	ctf_dict = dict_tmp;
> +      }
> +
> +    ctf_dict_close(ctf_dict);
> +    /* Canonicalize all the types generated above.  This must be
> +       done "a posteriori" because the processing of types may
> +       require other related types to not be already
> +       canonicalized.  */
> +    canonicalize_all_types();
> +  }
> +
> +  /// Add a new type declaration to the given libabigail IR corpus CORP.
> +  ///
> +  /// @param corp the libabigail IR corpus being constructed.
> +  /// @param tunit the current IR translation unit.
> +  /// @param ctf_dictionary the CTF dictionary being read.
> +  /// @param ctf_type the CTF type ID of the source type.
> +  ///
> +  /// Note that if @ref ctf_type can't reliably be translated to the IR
> +  /// then it is simply ignored.
> +  ///
> +  /// @return a shared pointer to the IR node for the type.
> +  type_base_sptr
> +  process_ctf_type(corpus_sptr corp,
> +		   translation_unit_sptr tunit,
> +		   ctf_dict_t *ctf_dictionary,
> +		   ctf_id_t ctf_type)
> +  {
> +    int type_kind = ctf_type_kind(ctf_dictionary, ctf_type);
> +    type_base_sptr result;
> +
> +    if (lookup_unknown_type(ctf_type))
> +      return nullptr;
> +
> +    if ((result = lookup_type(ctf_dictionary, ctf_type)))
> +      return result;
> +
> +    switch (type_kind)
> +      {
> +      case CTF_K_INTEGER:
> +      case CTF_K_FLOAT:
> +	{
> +	  type_decl_sptr type_decl
> +	    = process_ctf_base_type(this, corp, tunit, ctf_dictionary, ctf_type);
> +	  result = is_type(type_decl);
> +	  break;
> +	}
> +      case CTF_K_TYPEDEF:
> +	{
> +	  typedef_decl_sptr typedef_decl
> +	    = process_ctf_typedef(this, corp, tunit, ctf_dictionary, ctf_type);
> +	  result = is_type(typedef_decl);
> +	  break;
> +	}
> +      case CTF_K_POINTER:
> +	{
> +	  pointer_type_def_sptr pointer_type
> +	    = process_ctf_pointer_type(this, corp, tunit, ctf_dictionary, ctf_type);
> +	  result = pointer_type;
> +	  break;
> +	}
> +      case CTF_K_CONST:
> +      case CTF_K_VOLATILE:
> +      case CTF_K_RESTRICT:
> +	{
> +	  type_base_sptr qualified_type
> +	    = process_ctf_qualified_type(this, corp, tunit, ctf_dictionary, ctf_type);
> +	  result = qualified_type;
> +	  break;
> +	}
> +      case CTF_K_ARRAY:
> +	{
> +	  array_type_def_sptr array_type
> +	    = process_ctf_array_type(this, corp, tunit, ctf_dictionary, ctf_type);
> +	  result = array_type;
> +	  break;
> +	}
> +      case CTF_K_ENUM:
> +	{
> +	  enum_type_decl_sptr enum_type
> +	    = process_ctf_enum_type(this, tunit, ctf_dictionary, ctf_type);
> +	  result = enum_type;
> +	  break;
> +	}
> +      case CTF_K_FUNCTION:
> +	{
> +	  function_type_sptr function_type
> +	    = process_ctf_function_type(this, corp, tunit, ctf_dictionary, ctf_type);
> +	  result = function_type;
> +	  break;
> +	}
> +      case CTF_K_STRUCT:
> +	{
> +	  class_decl_sptr struct_decl
> +	    = process_ctf_struct_type(this, corp, tunit, ctf_dictionary, ctf_type);
> +	  result = is_type(struct_decl);
> +	  break;
> +	}
> +      case CTF_K_FORWARD:
> +	{
> +	  result = process_ctf_forward_type(this, tunit,
> +					    ctf_dictionary,
> +					    ctf_type);
> +	}
> +	break;
> +      case CTF_K_UNION:
> +	{
> +	  union_decl_sptr union_decl
> +	    = process_ctf_union_type(this, corp, tunit, ctf_dictionary, ctf_type);
> +	  result = is_type(union_decl);
> +	  break;
> +	}
> +      case CTF_K_UNKNOWN:
> +	/* Unknown types are simply ignored.  */
> +      default:
> +	break;
> +      }
> +
> +    if (!result)
> +      {
> +	fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
> +	add_unknown_type(ctf_type);
> +      }
> +
> +    return result;
> +  }
> +
> +  /// Given a CTF type id, lookup the corresponding libabigail IR type.
> +  /// If the IR type hasn't been generated yet, generate it.
> +  ///
> +  /// @param corp the libabigail IR corpus being constructed.
> +  /// @param tunit the current IR translation unit.
> +  /// @param ctf_dictionary the CTF dictionary being read.
> +  /// @param ctf_type the CTF type ID of the looked type.
> +  ///
> +  /// Note that if @ref ctf_type can't reliably be translated to the IR
> +  /// then a NULL shared pointer is returned.
> +  ///
> +  /// @return a shared pointer to the IR node for the type.
> +  type_base_sptr
> +  lookup_type(corpus_sptr corp,
> +	      translation_unit_sptr tunit, ctf_dict_t *ctf_dictionary,
> +	      ctf_id_t ctf_type)
> +  {
> +    type_base_sptr result = lookup_type(ctf_dictionary, ctf_type);
> +
> +    if (!result)
> +      result = process_ctf_type(corp, tunit, ctf_dictionary, ctf_type);
> +    return result;
> +  }
> +
> +  /// Read the CTF information in the binary and construct an ABI
> +  /// corpus from it.
> +  ///
> +  /// @param status output parameter.  Contains the status of the ABI
> +  /// corpus construction.
> +  ///
> +  /// @return the corpus created as a result of processing the debug
> +  /// information.
> +  corpus_sptr
> +  read_corpus(fe_iface::status &status)
> +  {
> +    corpus_sptr corp = corpus();
> +    status = fe_iface::STATUS_UNKNOWN;
> +
> +    bool is_linux_kernel = elf_helpers::is_linux_kernel(elf_handle());
> +    corpus::origin origin = corpus::CTF_ORIGIN;
> +
> +    if (is_linux_kernel)
> +      origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
> +    corp->set_origin(origin);
> +
> +    if (corpus_group())
> +      corpus_group()->add_corpus(corpus());
> +
> +    slurp_elf_info(status);
> +    if (!is_linux_kernel
> +	&& ((status & fe_iface::STATUS_DEBUG_INFO_NOT_FOUND) |
> +	    (status & fe_iface::STATUS_NO_SYMBOLS_FOUND)))
> +      return corp;
> +
> +    int errp;
> +    if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
> +	&& corpus_group())
> +      {
> +	if (ctfa == NULL)
> +	  {
> +	    std::string ctfa_filename;
> +	    if (find_ctfa_file(ctfa_filename))
> +	      ctfa = ctf_arc_open(ctfa_filename.c_str(), &errp);
> +	  }
> +      }
> +    else
> +      /* Build the ctfa from the contents of the relevant ELF sections,
> +	 and process the CTF archive in the read context, if any.
> +	 Information about the types, variables, functions, etc contained
> +	 in the archive are added to the given corpus.  */
> +      ctfa = ctf_arc_bufopen(&ctf_sect, &symtab_sect,
> +			     &strtab_sect, &errp);
> +
> +    env().canonicalization_is_done(false);
> +    if (ctfa == NULL)
> +      status |= fe_iface::STATUS_DEBUG_INFO_NOT_FOUND;
> +    else
> +      {
> +	process_ctf_archive(corp);
> +	corpus()->sort_functions();
> +	corpus()->sort_variables();
> +      }
> +
> +    env().canonicalization_is_done(true);
> +
> +    return corp;
>     }
>   
> -  ~read_context()
> +  /// Destructor of the CTF reader.
> +  ~reader()
>     {
>       ctf_close(ctfa);
>     }
> -}; // end class read_context.
> +}; // end class reader.
>   
> -/// Forward reference, needed because several of the process_ctf_*
> -/// functions below are indirectly recursive through this call.
> -static type_base_sptr lookup_type(read_context *ctxt,
> -                                  corpus_sptr corp,
> -                                  translation_unit_sptr tunit,
> -                                  ctf_dict_t *ctf_dictionary,
> -                                  ctf_id_t ctf_type);
> +typedef shared_ptr<reader> reader_sptr;
>   
>   /// Build and return a typedef libabigail IR.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the read context.
>   /// @param corp the libabigail IR corpus being constructed.
>   /// @param tunit the current IR translation unit.
>   /// @param ctf_dictionary the CTF dictionary being read.
> @@ -338,7 +730,7 @@ static type_base_sptr lookup_type(read_context *ctxt,
>   /// @return a shared pointer to the IR node for the typedef.
>   
>   static typedef_decl_sptr
> -process_ctf_typedef(read_context *ctxt,
> +process_ctf_typedef(reader *rdr,
>                       corpus_sptr corp,
>                       translation_unit_sptr tunit,
>                       ctf_dict_t *ctf_dictionary,
> @@ -351,17 +743,17 @@ process_ctf_typedef(read_context *ctxt,
>       return result;
>   
>     const char *typedef_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
> -  if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
> +  if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
>       if (result = lookup_typedef_type(typedef_name, *corp))
>         return result;
>   
> -  type_base_sptr utype = lookup_type(ctxt, corp, tunit,
> -                                     ctf_dictionary, ctf_utype);
> +  type_base_sptr utype = rdr->lookup_type(corp, tunit,
> +					  ctf_dictionary, ctf_utype);
>   
>     if (!utype)
>       return result;
>   
> -  result = dynamic_pointer_cast<typedef_decl>(ctxt->lookup_type(ctf_dictionary,
> +  result = dynamic_pointer_cast<typedef_decl>(rdr->lookup_type(ctf_dictionary,
>                                                                   ctf_type));
>     if (result)
>       return result;
> @@ -383,7 +775,7 @@ process_ctf_typedef(read_context *ctxt,
>     if (result)
>       {
>         add_decl_to_scope(result, tunit->get_global_scope());
> -      ctxt->add_type(ctf_dictionary, ctf_type, result);
> +      rdr->add_type(ctf_dictionary, ctf_type, result);
>       }
>   
>     return result;
> @@ -392,7 +784,7 @@ process_ctf_typedef(read_context *ctxt,
>   /// Build and return an integer or float type declaration libabigail
>   /// IR.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the read context.
>   /// @param corp the libabigail IR corpus being constructed.
>   /// @param ctf_dictionary the CTF dictionary being read.
>   /// @param ctf_type the CTF type ID of the source type.
> @@ -400,7 +792,7 @@ process_ctf_typedef(read_context *ctxt,
>   /// @return a shared pointer to the IR node for the type.
>   
>   static type_decl_sptr
> -process_ctf_base_type(read_context *ctxt,
> +process_ctf_base_type(reader *rdr,
>                         corpus_sptr corp,
>                         translation_unit_sptr tunit,
>                         ctf_dict_t *ctf_dictionary,
> @@ -425,14 +817,14 @@ process_ctf_base_type(read_context *ctxt,
>         && type_encoding.cte_format == CTF_INT_SIGNED)
>       {
>         /* This is the `void' type.  */
> -      type_base_sptr void_type = ctxt->ir_env->get_void_type();
> +      type_base_sptr void_type = rdr->env().get_void_type();
>         decl_base_sptr type_declaration = get_type_declaration(void_type);
>         result = is_type_decl(type_declaration);
>         canonicalize(result);
>       }
>     else
>       {
> -      if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
> +      if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
>           {
>             string normalized_type_name = type_name;
>             integral_type int_type;
> @@ -444,7 +836,7 @@ process_ctf_base_type(read_context *ctxt,
>   
>         result = lookup_basic_type(type_name, *corp);
>         if (!result)
> -        result.reset(new type_decl(ctxt->ir_env,
> +        result.reset(new type_decl(rdr->env(),
>                                      type_name,
>                                      type_encoding.cte_bits,
>                                      type_alignment * 8 /* in bits */,
> @@ -456,7 +848,7 @@ process_ctf_base_type(read_context *ctxt,
>     if (result)
>       {
>         add_decl_to_scope(result, tunit->get_global_scope());
> -      ctxt->add_type(ctf_dictionary, ctf_type, result);
> +      rdr->add_type(ctf_dictionary, ctf_type, result);
>       }
>   
>     return result;
> @@ -464,17 +856,16 @@ process_ctf_base_type(read_context *ctxt,
>   
>   /// Build the IR node for a variadic parameter type.
>   ///
> -/// @param ctxt the read context to use.
> +/// @param rdr the read context to use.
>   ///
>   /// @return the variadic parameter type.
>   static decl_base_sptr
> -build_ir_node_for_variadic_parameter_type(read_context &ctxt,
> +build_ir_node_for_variadic_parameter_type(reader &rdr,
>                                             translation_unit_sptr tunit)
>   {
>   
> -  ir::environment* env = ctxt.ir_env;
> -  ABG_ASSERT(env);
> -  type_base_sptr t = env->get_variadic_parameter_type();
> +  const ir::environment& env = rdr.env();
> +  type_base_sptr t = env.get_variadic_parameter_type();
>     decl_base_sptr type_declaration = get_type_declaration(t);
>     if (!has_scope(type_declaration))
>       add_decl_to_scope(type_declaration, tunit->get_global_scope());
> @@ -484,7 +875,7 @@ build_ir_node_for_variadic_parameter_type(read_context &ctxt,
>   
>   /// Build and return a function type libabigail IR.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the read context.
>   /// @param corp the libabigail IR corpus being constructed.
>   /// @param tunit the current IR translation unit.
>   /// @param ctf_dictionary the CTF dictionary being read.
> @@ -493,7 +884,7 @@ build_ir_node_for_variadic_parameter_type(read_context &ctxt,
>   /// @return a shared pointer to the IR node for the function type.
>   
>   static function_type_sptr
> -process_ctf_function_type(read_context *ctxt,
> +process_ctf_function_type(reader *rdr,
>                             corpus_sptr corp,
>                             translation_unit_sptr tunit,
>                             ctf_dict_t *ctf_dictionary,
> @@ -508,8 +899,8 @@ process_ctf_function_type(read_context *ctxt,
>   
>     /* Take care first of the result type.  */
>     ctf_id_t ctf_ret_type = funcinfo.ctc_return;
> -  type_base_sptr ret_type = lookup_type(ctxt, corp, tunit,
> -                                        ctf_dictionary, ctf_ret_type);
> +  type_base_sptr ret_type = rdr->lookup_type(corp, tunit,
> +					     ctf_dictionary, ctf_ret_type);
>     if (!ret_type)
>       return result;
>   
> @@ -524,8 +915,8 @@ process_ctf_function_type(read_context *ctxt,
>     for (int i = 0; i < argc; i++)
>       {
>         ctf_id_t ctf_arg_type = argv[i];
> -      type_base_sptr arg_type = lookup_type(ctxt, corp, tunit,
> -                                            ctf_dictionary, ctf_arg_type);
> +      type_base_sptr arg_type = rdr->lookup_type(corp, tunit,
> +						 ctf_dictionary, ctf_arg_type);
>         if (!arg_type)
>           return result;
>   
> @@ -540,7 +931,7 @@ process_ctf_function_type(read_context *ctxt,
>     if (vararg_p)
>       {
>         type_base_sptr arg_type =
> -       is_type(build_ir_node_for_variadic_parameter_type(*ctxt, tunit));
> +       is_type(build_ir_node_for_variadic_parameter_type(*rdr, tunit));
>   
>         function_decl::parameter_sptr parm
>          (new function_decl::parameter(arg_type, "",
> @@ -550,7 +941,7 @@ process_ctf_function_type(read_context *ctxt,
>         function_parms.push_back(parm);
>       }
>   
> -  result = dynamic_pointer_cast<function_type>(ctxt->lookup_type(ctf_dictionary,
> +  result = dynamic_pointer_cast<function_type>(rdr->lookup_type(ctf_dictionary,
>                                                                    ctf_type));
>     if (result)
>       return result;
> @@ -567,7 +958,7 @@ process_ctf_function_type(read_context *ctxt,
>         result->set_is_artificial(true);
>         decl_base_sptr function_type_decl = get_type_declaration(result);
>         add_decl_to_scope(function_type_decl, tunit->get_global_scope());
> -      ctxt->add_type(ctf_dictionary, ctf_type, result);
> +      rdr->add_type(ctf_dictionary, ctf_type, result);
>       }
>   
>     return result;
> @@ -575,7 +966,7 @@ process_ctf_function_type(read_context *ctxt,
>   
>   /// Add member information to a IR struct or union type.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the read context.
>   /// @param corp the libabigail IR corpus being constructed.
>   /// @param tunit the current IR translation unit.
>   /// @param ctf_dictionary the CTF dictionary being read.
> @@ -583,7 +974,7 @@ process_ctf_function_type(read_context *ctxt,
>   /// @param sou the IR struct or union type to which add the members.
>   
>   static void
> -process_ctf_sou_members(read_context *ctxt,
> +process_ctf_sou_members(reader *rdr,
>                           corpus_sptr corp,
>                           translation_unit_sptr tunit,
>                           ctf_dict_t *ctf_dictionary,
> @@ -609,9 +1000,9 @@ process_ctf_sou_members(read_context *ctxt,
>           return;
>   
>         /* Build the IR for the member's type.  */
> -      type_base_sptr member_type = lookup_type(ctxt, corp, tunit,
> -                                               ctf_dictionary,
> -                                               member_ctf_type);
> +      type_base_sptr member_type = rdr->lookup_type(corp, tunit,
> +						    ctf_dictionary,
> +						    member_ctf_type);
>         if (!member_type)
>           /* Ignore this member.  */
>           continue;
> @@ -635,14 +1026,14 @@ process_ctf_sou_members(read_context *ctxt,
>   /// Create a declaration-only union or struct type and add it to the
>   /// IR.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the read context.
>   /// @param tunit the current IR translation unit.
>   /// @param ctf_dictionary the CTF dictionary being read.
>   /// @param ctf_type the CTF type ID of the source type.
>   /// @return the resulting IR node created.
>   
>   static type_base_sptr
> -process_ctf_forward_type(read_context *ctxt,
> +process_ctf_forward_type(reader *rdr,
>                            translation_unit_sptr tunit,
>                            ctf_dict_t *ctf_dictionary,
>                            ctf_id_t ctf_type)
> @@ -656,24 +1047,24 @@ process_ctf_forward_type(read_context *ctxt,
>     if (kind == CTF_K_UNION)
>       {
>         union_decl_sptr
> -       union_fwd(new union_decl(ctxt->ir_env,
> -                                type_name,
> -                                /*alignment=*/0,
> -                                location(),
> -                                decl_base::VISIBILITY_DEFAULT,
> -                                type_is_anonymous));
> +	union_fwd(new union_decl(rdr->env(),
> +				 type_name,
> +				 /*alignment=*/0,
> +				 location(),
> +				 decl_base::VISIBILITY_DEFAULT,
> +				 type_is_anonymous));
>         union_fwd->set_is_declaration_only(true);
>         result = union_fwd;
>       }
>     else
>       {
>         if (!type_is_anonymous)
> -        if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
> +        if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
>             if (result = lookup_class_type(type_name, *corp))
>               return is_type(result);
>   
>         class_decl_sptr
> -       struct_fwd(new class_decl(ctxt->ir_env, type_name,
> +	struct_fwd(new class_decl(rdr->env(), type_name,
>                                    /*alignment=*/0, /*size=*/0,
>                                    true /* is_struct */,
>                                    location(),
> @@ -687,14 +1078,14 @@ process_ctf_forward_type(read_context *ctxt,
>       return is_type(result);
>   
>     add_decl_to_scope(result, tunit->get_global_scope());
> -  ctxt->add_type(ctf_dictionary, ctf_type, is_type(result));
> +  rdr->add_type(ctf_dictionary, ctf_type, is_type(result));
>   
>     return is_type(result);
>   }
>   
>   /// Build and return a struct type libabigail IR.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the read context.
>   /// @param corp the libabigail IR corpus being constructed.
>   /// @param tunit the current IR translation unit.
>   /// @param ctf_dictionary the CTF dictionary being read.
> @@ -703,7 +1094,7 @@ process_ctf_forward_type(read_context *ctxt,
>   /// @return a shared pointer to the IR node for the struct type.
>   
>   static class_decl_sptr
> -process_ctf_struct_type(read_context *ctxt,
> +process_ctf_struct_type(reader *rdr,
>                           corpus_sptr corp,
>                           translation_unit_sptr tunit,
>                           ctf_dict_t *ctf_dictionary,
> @@ -715,12 +1106,12 @@ process_ctf_struct_type(read_context *ctxt,
>     bool struct_type_is_anonymous = (struct_type_name == "");
>   
>     if (!struct_type_is_anonymous)
> -    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
> +    if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
>         if (result = lookup_class_type(struct_type_name, *corp))
>           return result;
>   
>     /* The libabigail IR encodes C struct types in `class' IR nodes.  */
> -  result.reset(new class_decl(ctxt->ir_env,
> +  result.reset(new class_decl(rdr->env(),
>                                 struct_type_name,
>                                 ctf_type_size(ctf_dictionary, ctf_type) * 8,
>                                 ctf_type_align(ctf_dictionary, ctf_type) * 8,
> @@ -737,12 +1128,12 @@ process_ctf_struct_type(read_context *ctxt,
>        at this point even if the members haven't been added to the IR
>        node yet.  */
>     add_decl_to_scope(result, tunit->get_global_scope());
> -  ctxt->add_type(ctf_dictionary, ctf_type, result);
> +  rdr->add_type(ctf_dictionary, ctf_type, result);
>   
>     /* Now add the struct members as specified in the CTF type description.
>        This is C, so named types can only be defined in the global
>        scope.  */
> -  process_ctf_sou_members(ctxt, corp, tunit, ctf_dictionary, ctf_type,
> +  process_ctf_sou_members(rdr, corp, tunit, ctf_dictionary, ctf_type,
>                             result);
>   
>     return result;
> @@ -750,7 +1141,7 @@ process_ctf_struct_type(read_context *ctxt,
>   
>   /// Build and return an union type libabigail IR.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the read context.
>   /// @param corp the libabigail IR corpus being constructed.
>   /// @param tunit the current IR translation unit.
>   /// @param ctf_dictionary the CTF dictionary being read.
> @@ -759,7 +1150,7 @@ process_ctf_struct_type(read_context *ctxt,
>   /// @return a shared pointer to the IR node for the union type.
>   
>   static union_decl_sptr
> -process_ctf_union_type(read_context *ctxt,
> +process_ctf_union_type(reader *rdr,
>                          corpus_sptr corp,
>                          translation_unit_sptr tunit,
>                          ctf_dict_t *ctf_dictionary,
> @@ -771,12 +1162,12 @@ process_ctf_union_type(read_context *ctxt,
>     bool union_type_is_anonymous = (union_type_name == "");
>   
>     if (!union_type_is_anonymous)
> -    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
> +    if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
>         if (result = lookup_union_type(union_type_name, *corp))
>           return result;
>   
>     /* Create the corresponding libabigail union IR node.  */
> -  result.reset(new union_decl(ctxt->ir_env,
> +  result.reset(new union_decl(rdr->env(),
>                                   union_type_name,
>                                   ctf_type_size(ctf_dictionary, ctf_type) * 8,
>                                   location(),
> @@ -791,12 +1182,12 @@ process_ctf_union_type(read_context *ctxt,
>        at this point even if the members haven't been added to the IR
>        node yet.  */
>     add_decl_to_scope(result, tunit->get_global_scope());
> -  ctxt->add_type(ctf_dictionary, ctf_type, result);
> +  rdr->add_type(ctf_dictionary, ctf_type, result);
>   
>     /* Now add the union members as specified in the CTF type description.
>        This is C, so named types can only be defined in the global
>        scope.  */
> -  process_ctf_sou_members(ctxt, corp, tunit, ctf_dictionary, ctf_type,
> +  process_ctf_sou_members(rdr, corp, tunit, ctf_dictionary, ctf_type,
>                             result);
>   
>     return result;
> @@ -804,7 +1195,7 @@ process_ctf_union_type(read_context *ctxt,
>   
>   /// Build and return an array type libabigail IR.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the read context.
>   /// @param corp the libabigail IR corpus being constructed.
>   /// @param tunit the current IR translation unit.
>   /// @param ctf_dictionary the CTF dictionary being read.
> @@ -813,7 +1204,7 @@ process_ctf_union_type(read_context *ctxt,
>   /// @return a shared pointer to the IR node for the array type.
>   
>   static array_type_def_sptr
> -process_ctf_array_type(read_context *ctxt,
> +process_ctf_array_type(reader *rdr,
>                          corpus_sptr corp,
>                          translation_unit_sptr tunit,
>                          ctf_dict_t *ctf_dictionary,
> @@ -834,20 +1225,20 @@ process_ctf_array_type(read_context *ctxt,
>     uint64_t nelems = ctf_ainfo.ctr_nelems;
>   
>     /* Make sure the element type is generated.  */
> -  type_base_sptr element_type = lookup_type(ctxt, corp, tunit,
> -                                            ctf_dictionary,
> -                                            ctf_element_type);
> +  type_base_sptr element_type = rdr->lookup_type(corp, tunit,
> +						 ctf_dictionary,
> +						 ctf_element_type);
>     if (!element_type)
>       return result;
>   
>     /* Ditto for the index type.  */
> -  type_base_sptr index_type = lookup_type(ctxt, corp, tunit,
> -                                          ctf_dictionary,
> -                                          ctf_index_type);
> +  type_base_sptr index_type = rdr->lookup_type(corp, tunit,
> +					       ctf_dictionary,
> +					       ctf_index_type);
>     if (!index_type)
>       return result;
>   
> -  result = dynamic_pointer_cast<array_type_def>(ctxt->lookup_type(ctf_dictionary,
> +  result = dynamic_pointer_cast<array_type_def>(rdr->lookup_type(ctf_dictionary,
>                                                                     ctf_type));
>     if (result)
>       return result;
> @@ -866,7 +1257,7 @@ process_ctf_array_type(read_context *ctxt,
>     if (upper_bound.get_unsigned_value() == 0)
>       is_infinite = true;
>   
> -  subrange.reset(new array_type_def::subrange_type(ctxt->ir_env,
> +  subrange.reset(new array_type_def::subrange_type(rdr->env(),
>                                                      "",
>                                                      lower_bound,
>                                                      upper_bound,
> @@ -887,7 +1278,7 @@ process_ctf_array_type(read_context *ctxt,
>       {
>         decl_base_sptr array_type_decl = get_type_declaration(result);
>         add_decl_to_scope(array_type_decl, tunit->get_global_scope());
> -      ctxt->add_type(ctf_dictionary, ctf_type, result);
> +      rdr->add_type(ctf_dictionary, ctf_type, result);
>       }
>   
>     return result;
> @@ -895,14 +1286,14 @@ process_ctf_array_type(read_context *ctxt,
>   
>   /// Build and return a qualified type libabigail IR.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the read context.
>   /// @param corp the libabigail IR corpus being constructed.
>   /// @param tunit the current IR translation unit.
>   /// @param ctf_dictionary the CTF dictionary being read.
>   /// @param ctf_type the CTF type ID of the source type.
>   
>   static type_base_sptr
> -process_ctf_qualified_type(read_context *ctxt,
> +process_ctf_qualified_type(reader *rdr,
>                              corpus_sptr corp,
>                              translation_unit_sptr tunit,
>                              ctf_dict_t *ctf_dictionary,
> @@ -911,12 +1302,12 @@ process_ctf_qualified_type(read_context *ctxt,
>     type_base_sptr result;
>     int type_kind = ctf_type_kind(ctf_dictionary, ctf_type);
>     ctf_id_t ctf_utype = ctf_type_reference(ctf_dictionary, ctf_type);
> -  type_base_sptr utype = lookup_type(ctxt, corp, tunit,
> -                                     ctf_dictionary, ctf_utype);
> +  type_base_sptr utype = rdr->lookup_type(corp, tunit,
> +					  ctf_dictionary, ctf_utype);
>     if (!utype)
>       return result;
>   
> -  result = dynamic_pointer_cast<type_base>(ctxt->lookup_type(ctf_dictionary,
> +  result = dynamic_pointer_cast<type_base>(rdr->lookup_type(ctf_dictionary,
>                                                                ctf_type));
>     if (result)
>       return result;
> @@ -940,7 +1331,7 @@ process_ctf_qualified_type(read_context *ctxt,
>       {
>         decl_base_sptr qualified_type_decl = get_type_declaration(result);
>         add_decl_to_scope(qualified_type_decl, tunit->get_global_scope());
> -      ctxt->add_type(ctf_dictionary, ctf_type, result);
> +      rdr->add_type(ctf_dictionary, ctf_type, result);
>       }
>   
>     return result;
> @@ -948,7 +1339,7 @@ process_ctf_qualified_type(read_context *ctxt,
>   
>   /// Build and return a pointer type libabigail IR.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the read context.
>   /// @param corp the libabigail IR corpus being constructed.
>   /// @param tunit the current IR translation unit.
>   /// @param ctf_dictionary the CTF dictionary being read.
> @@ -957,7 +1348,7 @@ process_ctf_qualified_type(read_context *ctxt,
>   /// @return a shared pointer to the IR node for the pointer type.
>   
>   static pointer_type_def_sptr
> -process_ctf_pointer_type(read_context *ctxt,
> +process_ctf_pointer_type(reader *rdr,
>                            corpus_sptr corp,
>                            translation_unit_sptr tunit,
>                            ctf_dict_t *ctf_dictionary,
> @@ -968,13 +1359,13 @@ process_ctf_pointer_type(read_context *ctxt,
>     if (ctf_target_type == CTF_ERR)
>       return result;
>   
> -  type_base_sptr target_type = lookup_type(ctxt, corp, tunit,
> -                                           ctf_dictionary,
> -                                           ctf_target_type);
> +  type_base_sptr target_type = rdr->lookup_type(corp, tunit,
> +						ctf_dictionary,
> +						ctf_target_type);
>     if (!target_type)
>       return result;
>   
> -  result = dynamic_pointer_cast<pointer_type_def>(ctxt->lookup_type(ctf_dictionary,
> +  result = dynamic_pointer_cast<pointer_type_def>(rdr->lookup_type(ctf_dictionary,
>                                                                       ctf_type));
>     if (result)
>       return result;
> @@ -986,7 +1377,7 @@ process_ctf_pointer_type(read_context *ctxt,
>     if (result)
>       {
>         add_decl_to_scope(result, tunit->get_global_scope());
> -      ctxt->add_type(ctf_dictionary, ctf_type, result);
> +      rdr->add_type(ctf_dictionary, ctf_type, result);
>       }
>   
>     return result;
> @@ -994,7 +1385,7 @@ process_ctf_pointer_type(read_context *ctxt,
>   
>   /// Build and return an enum type libabigail IR.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the read context.
>   /// @param corp the libabigail IR corpus being constructed.
>   /// @param tunit the current IR translation unit.
>   /// @param ctf_dictionary the CTF dictionary being read.
> @@ -1003,7 +1394,7 @@ process_ctf_pointer_type(read_context *ctxt,
>   /// @return a shared pointer to the IR node for the enum type.
>   
>   static enum_type_decl_sptr
> -process_ctf_enum_type(read_context *ctxt,
> +process_ctf_enum_type(reader *rdr,
>                         translation_unit_sptr tunit,
>                         ctf_dict_t *ctf_dictionary,
>                         ctf_id_t ctf_type)
> @@ -1012,7 +1403,7 @@ process_ctf_enum_type(read_context *ctxt,
>     std::string enum_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
>   
>     if (!enum_name.empty())
> -    if (corpus_sptr corp = ctxt->should_reuse_type_from_corpus_group())
> +    if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
>         if (result = lookup_enum_type(enum_name, *corp))
>           return result;
>   
> @@ -1022,7 +1413,7 @@ process_ctf_enum_type(read_context *ctxt,
>     size_t utype_size_in_bits = ctf_type_size(ctf_dictionary, ctf_type) * 8;
>     type_decl_sptr utype;
>   
> -  utype.reset(new type_decl(ctxt->ir_env,
> +  utype.reset(new type_decl(rdr->env(),
>                                 "",
>                                 utype_size_in_bits,
>                                 utype_size_in_bits,
> @@ -1041,7 +1432,7 @@ process_ctf_enum_type(read_context *ctxt,
>     int evalue;
>   
>     while ((ename = ctf_enum_next(ctf_dictionary, ctf_type, &enum_next, &evalue)))
> -    enms.push_back(enum_type_decl::enumerator(ctxt->ir_env, ename, evalue));
> +    enms.push_back(enum_type_decl::enumerator(ename, evalue));
>     if (ctf_errno(ctf_dictionary) != ECTF_NEXT_END)
>       {
>         fprintf(stderr, "ERROR from ctf_enum_next\n");
> @@ -1053,154 +1444,9 @@ process_ctf_enum_type(read_context *ctxt,
>     if (result)
>       {
>         add_decl_to_scope(result, tunit->get_global_scope());
> -      ctxt->add_type(ctf_dictionary, ctf_type, result);
> -    }
> -
> -  return result;
> -}
> -
> -/// Add a new type declaration to the given libabigail IR corpus CORP.
> -///
> -/// @param ctxt the read context.
> -/// @param corp the libabigail IR corpus being constructed.
> -/// @param tunit the current IR translation unit.
> -/// @param ctf_dictionary the CTF dictionary being read.
> -/// @param ctf_type the CTF type ID of the source type.
> -///
> -/// Note that if @ref ctf_type can't reliably be translated to the IR
> -/// then it is simply ignored.
> -///
> -/// @return a shared pointer to the IR node for the type.
> -
> -static type_base_sptr
> -process_ctf_type(read_context *ctxt,
> -                 corpus_sptr corp,
> -                 translation_unit_sptr tunit,
> -                 ctf_dict_t *ctf_dictionary,
> -                 ctf_id_t ctf_type)
> -{
> -  int type_kind = ctf_type_kind(ctf_dictionary, ctf_type);
> -  type_base_sptr result;
> -
> -  if (ctxt->lookup_unknown_type(ctf_type))
> -    return nullptr;
> -
> -  if ((result = ctxt->lookup_type(ctf_dictionary, ctf_type)))
> -    return result;
> -
> -  switch (type_kind)
> -    {
> -    case CTF_K_INTEGER:
> -    case CTF_K_FLOAT:
> -      {
> -        type_decl_sptr type_decl
> -          = process_ctf_base_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
> -        result = is_type(type_decl);
> -        break;
> -      }
> -    case CTF_K_TYPEDEF:
> -      {
> -        typedef_decl_sptr typedef_decl
> -          = process_ctf_typedef(ctxt, corp, tunit, ctf_dictionary, ctf_type);
> -        result = is_type(typedef_decl);
> -        break;
> -      }
> -    case CTF_K_POINTER:
> -      {
> -        pointer_type_def_sptr pointer_type
> -          = process_ctf_pointer_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
> -        result = pointer_type;
> -        break;
> -      }
> -    case CTF_K_CONST:
> -    case CTF_K_VOLATILE:
> -    case CTF_K_RESTRICT:
> -      {
> -        type_base_sptr qualified_type
> -          = process_ctf_qualified_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
> -        result = qualified_type;
> -        break;
> -      }
> -    case CTF_K_ARRAY:
> -      {
> -        array_type_def_sptr array_type
> -          = process_ctf_array_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
> -        result = array_type;
> -        break;
> -      }
> -    case CTF_K_ENUM:
> -      {
> -        enum_type_decl_sptr enum_type
> -          = process_ctf_enum_type(ctxt, tunit, ctf_dictionary, ctf_type);
> -        result = enum_type;
> -        break;
> -      }
> -    case CTF_K_FUNCTION:
> -      {
> -        function_type_sptr function_type
> -          = process_ctf_function_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
> -        result = function_type;
> -        break;
> -      }
> -    case CTF_K_STRUCT:
> -      {
> -        class_decl_sptr struct_decl
> -          = process_ctf_struct_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
> -        result = is_type(struct_decl);
> -        break;
> -      }
> -    case CTF_K_FORWARD:
> -      {
> -        result = process_ctf_forward_type(ctxt, tunit,
> -					  ctf_dictionary,
> -                                          ctf_type);
> -      }
> -      break;
> -    case CTF_K_UNION:
> -      {
> -        union_decl_sptr union_decl
> -          = process_ctf_union_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
> -        result = is_type(union_decl);
> -        break;
> -      }
> -    case CTF_K_UNKNOWN:
> -      /* Unknown types are simply ignored.  */
> -    default:
> -      break;
> +      rdr->add_type(ctf_dictionary, ctf_type, result);
>       }
>   
> -  if (!result)
> -    {
> -      fprintf(stderr, "NOT PROCESSED TYPE %lu\n", ctf_type);
> -      ctxt->add_unknown_type(ctf_type);
> -    }
> -
> -  return result;
> -}
> -
> -/// Given a CTF type id, lookup the corresponding libabigail IR type.
> -/// If the IR type hasn't been generated yet, generate it.
> -///
> -/// @param ctxt the read context.
> -/// @param corp the libabigail IR corpus being constructed.
> -/// @param tunit the current IR translation unit.
> -/// @param ctf_dictionary the CTF dictionary being read.
> -/// @param ctf_type the CTF type ID of the looked type.
> -///
> -/// Note that if @ref ctf_type can't reliably be translated to the IR
> -/// then a NULL shared pointer is returned.
> -///
> -/// @return a shared pointer to the IR node for the type.
> -
> -static type_base_sptr
> -lookup_type(read_context *ctxt, corpus_sptr corp,
> -            translation_unit_sptr tunit, ctf_dict_t *ctf_dictionary,
> -            ctf_id_t ctf_type)
> -{
> -  type_base_sptr result = ctxt->lookup_type(ctf_dictionary, ctf_type);
> -
> -  if (!result)
> -    result = process_ctf_type(ctxt, corp, tunit, ctf_dictionary, ctf_type);
>     return result;
>   }
>   
> @@ -1259,162 +1505,6 @@ lookup_symbol_in_ctf_archive(ctf_archive_t *ctfa, ctf_dict_t **ctf_dict,
>     return ctf_type;
>   }
>   
> -/// Process a CTF archive and create libabigail IR for the types,
> -/// variables and function declarations found in the archive, iterating
> -/// over public symbols.  The IR is added to the given corpus.
> -///
> -/// @param ctxt the read context containing the CTF archive to
> -/// process.
> -/// @param corp the IR corpus to which add the new contents.
> -
> -static void
> -process_ctf_archive(read_context *ctxt, corpus_sptr corp)
> -{
> -  /* We only have a translation unit.  */
> -  translation_unit_sptr ir_translation_unit =
> -    std::make_shared<translation_unit>(ctxt->ir_env, "", 64);
> -  ir_translation_unit->set_language(translation_unit::LANG_C);
> -  corp->add(ir_translation_unit);
> -
> -  int ctf_err;
> -  ctf_dict_t *ctf_dict, *dict_tmp;
> -  const auto symtab = ctxt->symtab;
> -  symtab_reader::symtab_filter filter = symtab->make_filter();
> -  filter.set_public_symbols();
> -  std::string dict_name;
> -
> -  if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
> -      && ctxt->cur_corpus_group_)
> -    {
> -      tools_utils::base_name(ctxt->filename, dict_name);
> -
> -      if (dict_name != "vmlinux")
> -        // remove .ko suffix
> -        dict_name.erase(dict_name.length() - 3, 3);
> -
> -      std::replace(dict_name.begin(), dict_name.end(), '-', '_');
> -    }
> -
> -  if ((ctf_dict = ctf_dict_open(ctxt->ctfa,
> -                                dict_name.empty() ? NULL : dict_name.c_str(),
> -                                &ctf_err)) == NULL)
> -    {
> -      fprintf(stderr, "ERROR dictionary not found\n");
> -      abort();
> -    }
> -
> -  dict_tmp = ctf_dict;
> -
> -  for (const auto& symbol : symtab_reader::filtered_symtab(*symtab, filter))
> -    {
> -      std::string sym_name = symbol->get_name();
> -      ctf_id_t ctf_sym_type;
> -
> -      ctf_sym_type = lookup_symbol_in_ctf_archive(ctxt->ctfa, &ctf_dict,
> -                                                  sym_name.c_str());
> -      if (ctf_sym_type == CTF_ERR)
> -          continue;
> -
> -      if (ctf_type_kind(ctf_dict, ctf_sym_type) != CTF_K_FUNCTION)
> -        {
> -          const char *var_name = sym_name.c_str();
> -          type_base_sptr var_type = lookup_type(ctxt, corp, ir_translation_unit,
> -                                                ctf_dict, ctf_sym_type);
> -          if (!var_type)
> -            /* Ignore variable if its type can't be sorted out.  */
> -            continue;
> -
> -          var_decl_sptr var_declaration;
> -          var_declaration.reset(new var_decl(var_name,
> -                                             var_type,
> -                                             location(),
> -                                             var_name));
> -
> -          var_declaration->set_symbol(symbol);
> -          add_decl_to_scope(var_declaration,
> -                            ir_translation_unit->get_global_scope());
> -          var_declaration->set_is_in_public_symbol_table(true);
> -          ctxt->maybe_add_var_to_exported_decls(var_declaration.get());
> -        }
> -      else
> -        {
> -          const char *func_name = sym_name.c_str();
> -          ctf_id_t ctf_sym = ctf_sym_type;
> -          type_base_sptr func_type = lookup_type(ctxt, corp, ir_translation_unit,
> -                                                 ctf_dict, ctf_sym);
> -          if (!func_type)
> -            /* Ignore function if its type can't be sorted out.  */
> -            continue;
> -
> -          function_decl_sptr func_declaration;
> -          func_declaration.reset(new function_decl(func_name,
> -                                                   func_type,
> -                                                   0 /* is_inline */,
> -                                                   location()));
> -          func_declaration->set_symbol(symbol);
> -          add_decl_to_scope(func_declaration,
> -                            ir_translation_unit->get_global_scope());
> -          func_declaration->set_is_in_public_symbol_table(true);
> -          ctxt->maybe_add_fn_to_exported_decls(func_declaration.get());
> -        }
> -
> -      ctf_dict = dict_tmp;
> -    }
> -
> -  ctf_dict_close(ctf_dict);
> -  /* Canonicalize all the types generated above.  This must be
> -     done "a posteriori" because the processing of types may
> -     require other related types to not be already
> -     canonicalized.  */
> -  ctxt->canonicalize_all_types();
> -}
> -
> -/// Open the ELF file described by the given read context.
> -///
> -/// @param ctxt the read context.
> -/// @return 0 if the ELF file can't be opened.
> -/// @return 1 otherwise.
> -
> -static int
> -open_elf_handler(read_context *ctxt)
> -{
> -  /* libelf requires to negotiate/set the version of ELF.  */
> -  if (elf_version(EV_CURRENT) == EV_NONE)
> -    return 0;
> -
> -  /* Open an ELF handler.  */
> -  ctxt->elf_fd = open(ctxt->filename.c_str(), O_RDONLY);
> -  if (ctxt->elf_fd == -1)
> -    return 0;
> -
> -  ctxt->elf_handler = elf_begin(ctxt->elf_fd, ELF_C_READ, NULL);
> -  if (ctxt->elf_handler == NULL)
> -    {
> -      fprintf(stderr, "cannot open %s: %s\n",
> -               ctxt->filename.c_str(), elf_errmsg(elf_errno()));
> -      close(ctxt->elf_fd);
> -      return 0;
> -    }
> -
> -  return 1;
> -}
> -
> -/// Close the ELF file described by the given read context.
> -///
> -/// @param ctxt the read context.
> -
> -static void
> -close_elf_handler (read_context *ctxt)
> -{
> -  /* Finish the ELF handler and close the associated file.  */
> -  elf_end(ctxt->elf_handler);
> -  close(ctxt->elf_fd);
> -
> -  /* Finish the ELF handler and close the associated debug file.  */
> -  elf_end(ctxt->elf_handler_dbg);
> -  close(ctxt->elf_fd_dbg);
> -}
> -
>   /// Fill a CTF section description with the information in a given ELF
>   /// section.
>   ///
> @@ -1422,13 +1512,14 @@ close_elf_handler (read_context *ctxt)
>   /// @param ctf_section the CTF section to fill with the raw data.
>   
>   static void
> -fill_ctf_section(Elf_Scn *elf_section, ctf_sect_t *ctf_section)
> +fill_ctf_section(const Elf_Scn *elf_section, ctf_sect_t *ctf_section)
>   {
>     GElf_Shdr section_header_mem, *section_header;
>     Elf_Data *section_data;
>   
> -  section_header = gelf_getshdr(elf_section, &section_header_mem);
> -  section_data = elf_getdata(elf_section, 0);
> +  section_header = gelf_getshdr(const_cast<Elf_Scn*>(elf_section),
> +				&section_header_mem);
> +  section_data = elf_getdata(const_cast<Elf_Scn*>(elf_section), 0);
>   
>     ABG_ASSERT (section_header != NULL);
>     ABG_ASSERT (section_data != NULL);
> @@ -1439,326 +1530,27 @@ fill_ctf_section(Elf_Scn *elf_section, ctf_sect_t *ctf_section)
>     ctf_section->cts_entsize = section_header->sh_entsize;
>   }
>   
> -/// Find a CTF section and debug symbols in a given ELF using
> -/// .gnu_debuglink section.
> -///
> -/// @param ctxt the read context.
> -/// @param ctf_dbg_section the CTF section to fill with the raw data.
> -static void
> -find_alt_debuginfo(read_context *ctxt, Elf_Scn **ctf_dbg_scn)
> -{
> -  std::string name;
> -  Elf_Data *data;
> -
> -  Elf_Scn *section = elf_helpers::find_section
> -    (ctxt->elf_handler, ".gnu_debuglink", SHT_PROGBITS);
> -
> -  if (section
> -      && (data = elf_getdata(section, NULL))
> -      && data->d_size != 0)
> -    name = (char *) data->d_buf;
> -
> -  int fd = -1;
> -  Elf *hdlr = NULL;
> -  *ctf_dbg_scn = NULL;
> -
> -  if (!name.empty())
> -    for (vector<char**>::const_iterator i = ctxt->debug_info_root_paths_.begin();
> -         i != ctxt->debug_info_root_paths_.end();
> -         ++i)
> -      {
> -        std::string file_path;
> -        if (!tools_utils::find_file_under_dir(**i, name, file_path))
> -          continue;
> -
> -        if ((fd = open(file_path.c_str(), O_RDONLY)) == -1)
> -          continue;
> -
> -        if ((hdlr = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
> -          {
> -            close(fd);
> -            continue;
> -          }
> -
> -        ctxt->symtab =
> -          symtab_reader::symtab::load(hdlr, ctxt->ir_env, nullptr);
> -
> -        // unlikely .ctf was designed to be present in stripped file
> -        *ctf_dbg_scn =
> -          elf_helpers::find_section(hdlr, ".ctf", SHT_PROGBITS);
> -          break;
> -
> -        elf_end(hdlr);
> -        close(fd);
> -      }
> -
> -  // If we don't have a symbol table, use current one in ELF file
> -  if (!ctxt->symtab)
> -    ctxt->symtab =
> -     symtab_reader::symtab::load(ctxt->elf_handler, ctxt->ir_env, nullptr);
> -
> -  ctxt->elf_handler_dbg = hdlr;
> -  ctxt->elf_fd_dbg = fd;
> -}
> -
> -/// Slurp certain information from the ELF file described by a given
> -/// read context and install it in a libabigail corpus.
> -///
> -/// @param ctxt the read context
> -/// @param corp the libabigail corpus in which to install the info.
> -/// @param status the resulting status flags.
> -static void
> -slurp_elf_info(read_context *ctxt,
> -               corpus_sptr corp,
> -               elf_reader::status& status)
> -{
> -  /* Set the ELF architecture.  */
> -  GElf_Ehdr *ehdr, eh_mem;
> -  Elf_Scn *symtab_scn;
> -  Elf_Scn *ctf_scn, *ctf_dbg_scn;
> -  Elf_Scn *strtab_scn;
> -
> -  if (!(ehdr = gelf_getehdr(ctxt->elf_handler, &eh_mem)))
> -      return;
> -
> -  corp->set_architecture_name(elf_helpers::e_machine_to_string(ehdr->e_machine));
> -
> -  find_alt_debuginfo(ctxt, &ctf_dbg_scn);
> -  ABG_ASSERT(ctxt->symtab);
> -  corp->set_symtab(ctxt->symtab);
> -
> -  if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
> -      && ctxt->cur_corpus_group_)
> -    {
> -      status |= elf_reader::STATUS_OK;
> -      return;
> -    }
> -
> -  /* Get the raw ELF section contents for libctf.  */
> -  const char *ctf_name = ".ctf";
> -  ctf_scn = elf_helpers::find_section_by_name(ctxt->elf_handler, ctf_name);
> -  if (ctf_scn == NULL)
> -    {
> -      if (ctf_dbg_scn)
> -        ctf_scn = ctf_dbg_scn;
> -      else
> -        {
> -          status |= elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
> -          return;
> -        }
> -    }
> -
> -  // ET_{EXEC,DYN} needs .dyn{sym,str} in ctf_arc_bufopen
> -  const char *symtab_name = ".dynsym";
> -  const char *strtab_name = ".dynstr";
> -
> -  if (ehdr->e_type == ET_REL)
> -    {
> -      symtab_name = ".symtab";
> -      strtab_name = ".strtab";
> -    }
> -
> -  symtab_scn = elf_helpers::find_section_by_name(ctxt->elf_handler, symtab_name);
> -  strtab_scn = elf_helpers::find_section_by_name(ctxt->elf_handler, strtab_name);
> -  if (symtab_scn == NULL || strtab_scn == NULL)
> -    {
> -      status |= elf_reader::STATUS_NO_SYMBOLS_FOUND;
> -      return;
> -    }
> -
> -  fill_ctf_section(ctf_scn, &ctxt->ctf_sect);
> -  fill_ctf_section(symtab_scn, &ctxt->symtab_sect);
> -  fill_ctf_section(strtab_scn, &ctxt->strtab_sect);
> -
> -  status |= elf_reader::STATUS_OK;
> -}
> -
> -/// Looks for vmlinux.ctfa file in default directory or in
> -/// directories provided by debug-info-dir command line option,
> -/// it stores location path in @ref ctfa_file.
> -///
> -/// @param ctxt the read context.
> -/// @param ctfa_file file name found.
> -/// @return true if file is found.
> -static bool
> -find_ctfa_file(read_context *ctxt, std::string& ctfa_file)
> -{
> -  std::string ctfa_dirname;
> -  dir_name(ctxt->filename, ctfa_dirname, false);
> -
> -  // In corpus group we assume vmlinux as first file to
> -  // be processed, so default location for vmlinux.cfa
> -  // is vmlinux dirname.
> -  ctfa_file = ctfa_dirname + "/vmlinux.ctfa";
> -  if (file_exists(ctfa_file))
> -    return true;
> -
> -  // If it's proccessing a module, then location directory
> -  // for vmlinux.ctfa should be provided with --debug-info-dir
> -  // option.
> -  for (vector<char**>::const_iterator i = ctxt->debug_info_root_paths_.begin();
> -       i != ctxt->debug_info_root_paths_.end();
> -       ++i)
> -    {
> -      ctfa_dirname = **i;
> -      ctfa_file = ctfa_dirname + "/vmlinux.ctfa";
> -      if (file_exists(ctfa_file))
> -        return true;
> -    }
> -
> -  return false;
> -}
> -
>   /// Create and return a new read context to process CTF information
>   /// from a given ELF file.
>   ///
>   /// @param elf_path the patch of some ELF file.
>   /// @param env a libabigail IR environment.
>   
> -read_context_sptr
> -create_read_context(const std::string& elf_path,
> -                    const vector<char**>& debug_info_root_paths,
> -                    ir::environment *env)
> -{
> -  read_context_sptr result(new read_context(elf_path,
> -                                            debug_info_root_paths,
> -                                            env));
> -  return result;
> -}
> -
> -/// Read the CTF information from some source described by a given
> -/// read context and process it to create a libabigail IR corpus.
> -/// Store the corpus in the same read context.
> -///
> -/// @param ctxt the read context to use.
> -///
> -/// @param status the resulting status of the corpus read.
> -///
> -/// @return a shared pointer to the read corpus.
> -
> -corpus_sptr
> -read_corpus(read_context *ctxt, elf_reader::status &status)
> -{
> -  corpus_sptr corp
> -    = std::make_shared<corpus>(ctxt->ir_env, ctxt->filename);
> -  ctxt->cur_corpus_ = corp;
> -  status = elf_reader::STATUS_UNKNOWN;
> -
> -  /* Open the ELF file.  */
> -  if (!open_elf_handler(ctxt))
> -      return corp;
> -
> -  bool is_linux_kernel = elf_helpers::is_linux_kernel(ctxt->elf_handler);
> -  corpus::origin origin = corpus::CTF_ORIGIN;
> -
> -  if (is_linux_kernel)
> -    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
> -  corp->set_origin(origin);
> -
> -  if (ctxt->cur_corpus_group_)
> -    ctxt->cur_corpus_group_->add_corpus(ctxt->cur_corpus_);
> -
> -  slurp_elf_info(ctxt, corp, status);
> -  if (!is_linux_kernel
> -      && ((status & elf_reader::STATUS_DEBUG_INFO_NOT_FOUND) |
> -          (status & elf_reader::STATUS_NO_SYMBOLS_FOUND)))
> -      return corp;
> -
> -  // Set the set of exported declaration that are defined.
> -  ctxt->exported_decls_builder
> -   (ctxt->cur_corpus_->get_exported_decls_builder().get());
> -
> -  int errp;
> -  if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
> -      && ctxt->cur_corpus_group_)
> -    {
> -      if (ctxt->ctfa == NULL)
> -        {
> -          std::string ctfa_filename;
> -          if (find_ctfa_file(ctxt, ctfa_filename))
> -            ctxt->ctfa = ctf_arc_open(ctfa_filename.c_str(), &errp);
> -        }
> -    }
> -  else
> -    /* Build the ctfa from the contents of the relevant ELF sections,
> -       and process the CTF archive in the read context, if any.
> -       Information about the types, variables, functions, etc contained
> -       in the archive are added to the given corpus.  */
> -    ctxt->ctfa = ctf_arc_bufopen(&ctxt->ctf_sect, &ctxt->symtab_sect,
> -                                 &ctxt->strtab_sect, &errp);
> -
> -  ctxt->ir_env->canonicalization_is_done(false);
> -  if (ctxt->ctfa == NULL)
> -    status |= elf_reader::STATUS_DEBUG_INFO_NOT_FOUND;
> -  else
> -    {
> -      process_ctf_archive(ctxt, corp);
> -      ctxt->cur_corpus_->sort_functions();
> -      ctxt->cur_corpus_->sort_variables();
> -    }
> -
> -  ctxt->ir_env->canonicalization_is_done(true);
> -
> -  /* Cleanup and return.  */
> -  close_elf_handler(ctxt);
> -  return corp;
> -}
> -
> -/// Read the CTF information from some source described by a given
> -/// read context and process it to create a libabigail IR corpus.
> -/// Store the corpus in the same read context.
> -///
> -/// @param ctxt the read context to use.
> -///
> -/// @param status the resulting status of the corpus read.
> -///
> -/// @return a shared pointer to the read corpus.
> -
> -corpus_sptr
> -read_corpus(const read_context_sptr &ctxt, elf_reader::status &status)
> -{return read_corpus(ctxt.get(), status);}
> -
> -/// Set the @ref corpus_group being created to the current read context.
> -///
> -/// @param ctxt the read_context to consider.
> -///
> -/// @param group the @ref corpus_group to set.
> -void
> -set_read_context_corpus_group(read_context& ctxt,
> -                              corpus_group_sptr& group)
> -{
> -  ctxt.cur_corpus_group_ = group;
> -}
> -
> -/// Read a corpus and add it to a given @ref corpus_group.
> -///
> -/// @param ctxt the reading context to consider.
> -///
> -/// @param group the @ref corpus_group to add the new corpus to.
> -///
> -/// @param status output parameter. The status of the read.  It is set
> -/// by this function upon its completion.
> -corpus_sptr
> -read_and_add_corpus_to_group_from_elf(read_context* ctxt,
> -                                      corpus_group& group,
> -                                      elf_reader::status& status)
> +elf_based_reader_sptr
> +create_ctf_reader(const std::string& elf_path,
> +		  const vector<char**>& debug_info_root_paths,
> +		  environment& env)
>   {
> -  corpus_sptr result;
> -  corpus_sptr corp = read_corpus(ctxt, status);
> -  if (status & elf_reader::STATUS_OK)
> -    {
> -      if (!corp->get_group())
> -        group.add_corpus(corp);
> -      result = corp;
> -    }
> -
> +  reader_sptr result(new reader(elf_path,
> +				debug_info_root_paths,
> +				env));
>     return result;
>   }
>   
> -/// Re-initialize a read_context so that it can re-used to read
> +/// Re-initialize a reader so that it can re-used to read
>   /// another binary.
>   ///
> -/// @param ctxt the context to re-initialize.
> +/// @param rdr the context to re-initialize.
>   ///
>   /// @param elf_path the path to the elf file the context is to be used
>   /// for.
> @@ -1771,16 +1563,15 @@ read_and_add_corpus_to_group_from_elf(read_context* ctxt,
>   ///
>   /// Please also note that the life time of this environment object
>   /// must be greater than the life time of the resulting @ref
> -/// read_context the context uses resources that are allocated in the
> +/// reader the context uses resources that are allocated in the
>   /// environment.
>   void
> -reset_read_context(read_context_sptr	&ctxt,
> -                   const std::string&	 elf_path,
> -                   const vector<char**>& debug_info_root_path,
> -                   ir::environment*	 environment)
> +reset_reader(elf_based_reader&		rdr,
> +	     const std::string&	elf_path,
> +	     const vector<char**>&	debug_info_root_path)
>   {
> -  if (ctxt)
> -    ctxt->initialize(elf_path, debug_info_root_path, environment);
> +  ctf_reader::reader& r = dynamic_cast<reader&>(rdr);
> +  r.initialize(elf_path, debug_info_root_path);
>   }
>   
>   /// Returns a key to be use in types_map dict conformed by
> @@ -1796,7 +1587,7 @@ reset_read_context(read_context_sptr	&ctxt,
>   /// was found.
>   ///
>   /// @param type the id for given CTF type.
> -std::string
> +static std::string
>   dic_type_key(ctf_dict_t *dic, ctf_id_t ctf_type)
>   {
>     std::stringstream key;
> diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
> index ddd040e1..70c85161 100644
> --- a/src/abg-dwarf-reader.cc
> +++ b/src/abg-dwarf-reader.cc
> @@ -11,7 +11,7 @@
>   /// de-serialize an instance of @ref abigail::corpus from a file in
>   /// elf format, containing dwarf information.
>   
> -#include "config.h"
> +#include "abg-internal.h"
>   #include <sys/types.h>
>   #include <sys/stat.h>
>   #include <fcntl.h>
> @@ -37,16 +37,16 @@
>   #include "abg-ir-priv.h"
>   #include "abg-suppression-priv.h"
>   #include "abg-corpus-priv.h"
> -#include "abg-elf-helpers.h"
> -#include "abg-internal.h"
> +#include "abg-symtab-reader.h"
>   
>   // <headers defining libabigail's API go under here>
>   ABG_BEGIN_EXPORT_DECLARATIONS
>   
>   #include "abg-dwarf-reader.h"
> +#include "abg-elf-based-reader.h"
>   #include "abg-sptr-utils.h"
> -#include "abg-symtab-reader.h"
>   #include "abg-tools-utils.h"
> +#include "abg-elf-helpers.h"
>   
>   ABG_END_EXPORT_DECLARATIONS
>   // </headers defining libabigail's API>
> @@ -91,16 +91,6 @@ enum die_source
>   				// enumerator
>   };
>   
> -/// A functor used by @ref dwfl_sptr.
> -struct dwfl_deleter
> -{
> -  void
> -  operator()(Dwfl* dwfl)
> -  {dwfl_end(dwfl);}
> -};//end struct dwfl_deleter
> -
> -/// A convenience typedef for a shared pointer to a Dwfl.
> -typedef shared_ptr<Dwfl> dwfl_sptr;
>   
>   /// A convenience typedef for a vector of Dwarf_Off.
>   typedef vector<Dwarf_Off> dwarf_offsets_type;
> @@ -143,13 +133,6 @@ typedef unordered_map<interned_string,
>   		      hash_interned_string>
>   istring_dwarf_offsets_map_type;
>   
> -/// Convenience typedef for a map which key is an elf address and
> -/// which value is an elf_symbol_sptr.
> -typedef unordered_map<GElf_Addr, elf_symbol_sptr> addr_elf_symbol_sptr_map_type;
> -
> -/// Convenience typedef for a set of ELF addresses.
> -typedef unordered_set<GElf_Addr> address_set_type;
> -
>   /// A hasher for a pair of Dwarf_Off.  This is used as a hasher for
>   /// the type @ref dwarf_offset_pair_set_type.
>   struct dwarf_offset_pair_hash
> @@ -244,21 +227,23 @@ typedef unordered_map<std::pair<offset_type, offset_type>,
>   /// A convenience typedef for a vector of pairs of offset_type.
>   typedef vector<std::pair<offset_type, offset_type>> offset_pair_vector_type;
>   
> -class read_context;
> +class reader;
> +
> +static translation_unit_sptr
> +build_translation_unit_and_add_to_ir(reader&	rdr,
> +				     Dwarf_Die*	die,
> +				     char		address_size);
>   
>   static void
> -maybe_propagate_canonical_type(const read_context& ctxt,
> +maybe_propagate_canonical_type(const reader& rdr,
>   			       const Dwarf_Die* l,
>   			       const Dwarf_Die* r);
>   
>   static void
> -propagate_canonical_type(const read_context& ctxt,
> +propagate_canonical_type(const reader& rdr,
>   			 const Dwarf_Die* l,
>   			 const Dwarf_Die* r);
>   
> -/// Convenience typedef for a shared pointer to an @ref address_set_type.
> -typedef shared_ptr<address_set_type> address_set_sptr;
> -
>   /// Convenience typedef for a shared pointer to an
>   /// addr_elf_symbol_sptr_map_type.
>   typedef shared_ptr<addr_elf_symbol_sptr_map_type> addr_elf_symbol_sptr_map_sptr;
> @@ -379,13 +364,13 @@ operator<(const imported_unit_point& l, const imported_unit_point& r)
>   {return l.offset_of_import < r.offset_of_import;}
>   
>   static bool
> -get_parent_die(const read_context&	ctxt,
> +get_parent_die(const reader&	rdr,
>   	       const Dwarf_Die*	die,
>   	       Dwarf_Die&		parent_die,
>   	       size_t			where_offset);
>   
>   static bool
> -get_scope_die(const read_context&	ctxt,
> +get_scope_die(const reader&	rdr,
>   	      const Dwarf_Die*		die,
>   	      size_t			where_offset,
>   	      Dwarf_Die&		scope_die);
> @@ -468,7 +453,7 @@ static bool
>   is_type_die_to_be_canonicalized(const Dwarf_Die *die);
>   
>   static bool
> -die_is_at_class_scope(const read_context& ctxt,
> +die_is_at_class_scope(const reader& rdr,
>   		      const Dwarf_Die* die,
>   		      size_t where_offset,
>   		      Dwarf_Die& class_scope_die);
> @@ -510,7 +495,7 @@ static string
>   die_name(const Dwarf_Die* die);
>   
>   static location
> -die_location(const read_context& ctxt, const Dwarf_Die* die);
> +die_location(const reader& rdr, const Dwarf_Die* die);
>   
>   static bool
>   die_location_address(Dwarf_Die*	die,
> @@ -540,27 +525,27 @@ build_internal_underlying_enum_type_name(const string &base_name,
>   					 uint64_t size);
>   
>   static string
> -die_qualified_type_name(const read_context& ctxt,
> +die_qualified_type_name(const reader& rdr,
>   			const Dwarf_Die* die,
>   			size_t where);
>   
>   static string
> -die_qualified_decl_name(const read_context& ctxt,
> +die_qualified_decl_name(const reader& rdr,
>   			const Dwarf_Die* die,
>   			size_t where);
>   
>   static string
> -die_qualified_name(const read_context& ctxt,
> +die_qualified_name(const reader& rdr,
>   		   const Dwarf_Die* die,
>   		   size_t where);
>   
>   static bool
> -die_qualified_type_name_empty(const read_context& ctxt,
> +die_qualified_type_name_empty(const reader& rdr,
>   			      const Dwarf_Die* die, size_t where,
>   			      string &qualified_name);
>   
>   static void
> -die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
> +die_return_and_parm_names_from_fn_type_die(const reader& rdr,
>   					   const Dwarf_Die* die,
>   					   size_t where_offset,
>   					   bool pretty_print,
> @@ -571,7 +556,7 @@ die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
>   					   bool& is_static);
>   
>   static string
> -die_function_signature(const read_context& ctxt,
> +die_function_signature(const reader& rdr,
>   		       const Dwarf_Die *die,
>   		       size_t where_offset);
>   
> @@ -579,7 +564,7 @@ static bool
>   die_peel_qual_ptr(Dwarf_Die *die, Dwarf_Die& peeled_die);
>   
>   static bool
> -die_function_type_is_method_type(const read_context& ctxt,
> +die_function_type_is_method_type(const reader& rdr,
>   				 const Dwarf_Die *die,
>   				 size_t where_offset,
>   				 Dwarf_Die& object_pointer_die,
> @@ -587,23 +572,23 @@ die_function_type_is_method_type(const read_context& ctxt,
>   				 bool& is_static);
>   
>   static string
> -die_pretty_print_type(read_context& ctxt,
> +die_pretty_print_type(reader& rdr,
>   		      const Dwarf_Die* die,
>   		      size_t where_offset);
>   
>   static string
> -die_pretty_print_decl(read_context& ctxt,
> +die_pretty_print_decl(reader& rdr,
>   		      const Dwarf_Die* die,
>   		      size_t where_offset);
>   
>   static string
> -die_pretty_print(read_context& ctxt,
> +die_pretty_print(reader& rdr,
>   		 const Dwarf_Die* die,
>   		 size_t where_offset);
>   
>   static void
>   maybe_canonicalize_type(const type_base_sptr&	t,
> -			read_context&		ctxt);
> +			reader&		rdr);
>   
>   static uint64_t
>   get_default_array_lower_bound(translation_unit::language l);
> @@ -614,234 +599,31 @@ find_lower_bound_in_imported_unit_points(const imported_unit_points_type&,
>   					 imported_unit_points_type::const_iterator&);
>   
>   static array_type_def::subrange_sptr
> -build_subrange_type(read_context&	ctxt,
> +build_subrange_type(reader&	rdr,
>   		    const Dwarf_Die*	die,
>   		    size_t		where_offset,
>   		    bool		associate_type_to_die = true);
>   
>   static void
> -build_subranges_from_array_type_die(read_context&			ctxt,
> +build_subranges_from_array_type_die(reader&			rdr,
>   				    const Dwarf_Die*			die,
>   				    array_type_def::subranges_type&	subranges,
>   				    size_t				where_offset,
>   				    bool				associate_type_to_die = true);
>   
>   static comparison_result
> -compare_dies(const read_context& ctxt,
> +compare_dies(const reader& rdr,
>   	     const Dwarf_Die *l, const Dwarf_Die *r,
>   	     bool update_canonical_dies_on_the_fly);
>   
>   static bool
> -compare_dies_during_canonicalization(read_context& ctxt,
> +compare_dies_during_canonicalization(reader& rdr,
>   				     const Dwarf_Die *l, const Dwarf_Die *r,
>   				     bool update_canonical_dies_on_the_fly);
>   
> -
>   static bool
>   get_member_child_die(const Dwarf_Die *die, Dwarf_Die *child);
>   
> -/// Find the file name of the alternate debug info file.
> -///
> -/// @param elf_module the elf module to consider.
> -///
> -/// @param out parameter.  Is set to the file name of the alternate
> -/// debug info file, iff this function returns true.
> -///
> -/// @return true iff the location of the alternate debug info file was
> -/// found.
> -static bool
> -find_alt_debug_info_link(Dwfl_Module *elf_module,
> -			 string &alt_file_name)
> -{
> -  GElf_Addr bias = 0;
> -  Dwarf *dwarf = dwfl_module_getdwarf(elf_module, &bias);
> -  Elf *elf = dwarf_getelf(dwarf);
> -  GElf_Ehdr ehmem, *elf_header;
> -  elf_header = gelf_getehdr(elf, &ehmem);
> -
> -  Elf_Scn* section = 0;
> -  while ((section = elf_nextscn(elf, section)) != 0)
> -    {
> -      GElf_Shdr header_mem, *header;
> -      header = gelf_getshdr(section, &header_mem);
> -      if (header->sh_type != SHT_PROGBITS)
> -	continue;
> -
> -      const char *section_name = elf_strptr(elf,
> -					    elf_header->e_shstrndx,
> -					    header->sh_name);
> -
> -      char *alt_name = 0;
> -      char *buildid = 0;
> -      size_t buildid_len = 0;
> -      if (section_name != 0
> -	  && strcmp(section_name, ".gnu_debugaltlink") == 0)
> -	{
> -	  Elf_Data *data = elf_getdata(section, 0);
> -	  if (data != 0 && data->d_size != 0)
> -	    {
> -	      alt_name = (char*) data->d_buf;
> -	      char *end_of_alt_name =
> -		(char *) memchr(alt_name, '\0', data->d_size);
> -	      buildid_len = data->d_size - (end_of_alt_name - alt_name + 1);
> -	      if (buildid_len == 0)
> -		return false;
> -	      buildid = end_of_alt_name + 1;
> -	    }
> -	}
> -      else
> -	continue;
> -
> -      if (buildid == 0 || alt_name == 0)
> -	return false;
> -
> -      alt_file_name = alt_name;
> -      return true;
> -    }
> -
> -  return false;
> -}
> -
> -/// Find alternate debuginfo file of a given "link" under a set of
> -/// root directories.
> -///
> -/// The link is a string that is read by the function
> -/// find_alt_debug_info_link().  That link is a path that is relative
> -/// to a given debug info file, e.g, "../../../.dwz/something.debug".
> -/// It designates the alternate debug info file associated to a given
> -/// debug info file.
> -///
> -/// This function will thus try to find the .dwz/something.debug file
> -/// under some given root directories.
> -///
> -/// @param root_dirs the set of root directories to look from.
> -///
> -/// @param alt_file_name a relative path to the alternate debug info
> -/// file to look for.
> -///
> -/// @param alt_file_path the resulting absolute path to the alternate
> -/// debuginfo path denoted by @p alt_file_name and found under one of
> -/// the directories in @p root_dirs.  This is set iff the function
> -/// returns true.
> -///
> -/// @return true iff the function found the alternate debuginfo file.
> -static bool
> -find_alt_debug_info_path(const vector<char**> root_dirs,
> -			 const string &alt_file_name,
> -			 string &alt_file_path)
> -{
> -  if (alt_file_name.empty())
> -    return false;
> -
> -  string altfile_name = tools_utils::trim_leading_string(alt_file_name, "../");
> -
> -  for (vector<char**>::const_iterator i = root_dirs.begin();
> -       i != root_dirs.end();
> -       ++i)
> -    if (tools_utils::find_file_under_dir(**i, altfile_name, alt_file_path))
> -      return true;
> -
> -  return false;
> -}
> -
> -/// Return the alternate debug info associated to a given main debug
> -/// info file.
> -///
> -/// @param elf_module the elf module to consider.
> -///
> -/// @param debug_root_dirs a set of root debuginfo directories under
> -/// which too look for the alternate debuginfo file.
> -///
> -/// @param alt_file_name output parameter.  This is set to the file
> -/// path of the alternate debug info file associated to @p elf_module.
> -/// This is set iff the function returns a non-null result.
> -///
> -/// @param alt_fd the file descriptor used to access the alternate
> -/// debug info.  If this parameter is set by the function, then the
> -/// caller needs to fclose it, otherwise the file descriptor is going
> -/// to be leaked.  Note however that on recent versions of elfutils
> -/// where libdw.h contains the function dwarf_getalt(), this parameter
> -/// is set to 0, so it doesn't need to be fclosed.
> -///
> -/// Note that the alternate debug info file is a DWARF extension as of
> -/// DWARF 4 ans is decribed at
> -/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
> -///
> -/// @return the alternate debuginfo, or null.  If @p alt_fd is
> -/// non-zero, then the caller of this function needs to call
> -/// dwarf_end() on the returned alternate debuginfo pointer,
> -/// otherwise, it's going to be leaked.
> -static Dwarf*
> -find_alt_debug_info(Dwfl_Module *elf_module,
> -		    const vector<char**> debug_root_dirs,
> -		    string& alt_file_name,
> -		    int& alt_fd)
> -{
> -  if (elf_module == 0)
> -    return 0;
> -
> -  Dwarf* result = 0;
> -  find_alt_debug_info_link(elf_module, alt_file_name);
> -
> -#ifdef LIBDW_HAS_DWARF_GETALT
> -  // We are on recent versions of elfutils where the function
> -  // dwarf_getalt exists, so let's use it.
> -  Dwarf_Addr bias = 0;
> -  Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
> -  result = dwarf_getalt(dwarf);
> -  alt_fd = 0;
> -#else
> -  // We are on an old version of elfutils where the function
> -  // dwarf_getalt doesn't exist yet, so let's open code its
> -  // functionality
> -  char *alt_name = 0;
> -  const char *file_name = 0;
> -  void **user_data = 0;
> -  Dwarf_Addr low_addr = 0;
> -  char *alt_file = 0;
> -
> -  file_name = dwfl_module_info(elf_module, &user_data,
> -			       &low_addr, 0, 0, 0, 0, 0);
> -
> -  alt_fd = dwfl_standard_find_debuginfo(elf_module, user_data,
> -					file_name, low_addr,
> -					alt_name, file_name,
> -					0, &alt_file);
> -
> -  result = dwarf_begin(alt_fd, DWARF_C_READ);
> -#endif
> -
> -  if (result == 0)
> -    {
> -      // So we didn't find the alternate debuginfo file from the
> -      // information that is in the debuginfo file associated to
> -      // elf_module.  Maybe the alternate debuginfo file is located
> -      // under one of the directories in debug_root_dirs.  So let's
> -      // look in there.
> -      string alt_file_path;
> -      if (!find_alt_debug_info_path(debug_root_dirs,
> -				    alt_file_name,
> -				    alt_file_path))
> -	return result;
> -
> -      // If we reach this point it means we have found the path to the
> -      // alternate debuginfo file and it's in alt_file_path.  So let's
> -      // open it and read it.
> -      int fd = open(alt_file_path.c_str(), O_RDONLY);
> -      if (fd == -1)
> -	return result;
> -      result = dwarf_begin(fd, DWARF_C_READ);
> -
> -#ifdef LIBDW_HAS_DWARF_GETALT
> -      Dwarf_Addr bias = 0;
> -      Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
> -      dwarf_setalt(dwarf, result);
> -#endif
> -    }
> -
> -  return result;
> -}
> -
>   /// Compare a symbol name against another name, possibly demangling
>   /// the symbol_name before performing the comparison.
>   ///
> @@ -892,7 +674,7 @@ compare_symbol_name(const string& symbol_name,
>   /// @param syms_found a vector of symbols found with the name @p
>   /// sym_name.  table.
>   static bool
> -lookup_symbol_from_sysv_hash_tab(const environment*		env,
> +lookup_symbol_from_sysv_hash_tab(const environment&		env,
>   				 Elf*				elf_handle,
>   				 const string&			sym_name,
>   				 size_t			ht_index,
> @@ -1169,7 +951,7 @@ setup_gnu_ht(Elf* elf_handle,
>   ///
>   /// @return true if a symbol was actually found.
>   static bool
> -lookup_symbol_from_gnu_hash_tab(const environment*		env,
> +lookup_symbol_from_gnu_hash_tab(const environment&		env,
>   				Elf*				elf_handle,
>   				const string&			sym_name,
>   				size_t				ht_index,
> @@ -1301,7 +1083,7 @@ lookup_symbol_from_gnu_hash_tab(const environment*		env,
>   /// @return true iff the function found the symbol from the elf hash
>   /// table.
>   static bool
> -lookup_symbol_from_elf_hash_tab(const environment*		env,
> +lookup_symbol_from_elf_hash_tab(const environment&		env,
>   				Elf*				elf_handle,
>   				hash_table_kind		ht_kind,
>   				size_t				ht_index,
> @@ -1358,7 +1140,7 @@ lookup_symbol_from_elf_hash_tab(const environment*		env,
>   ///
>   /// @return true iff the symbol was found.
>   static bool
> -lookup_symbol_from_symtab(const environment*		env,
> +lookup_symbol_from_symtab(environment&			env,
>   			  Elf*				elf_handle,
>   			  const string&		sym_name,
>   			  size_t			sym_tab_index,
> @@ -1449,7 +1231,7 @@ lookup_symbol_from_symtab(const environment*		env,
>   ///
>   /// @return true iff a symbol with the name @p symbol_name was found.
>   static bool
> -lookup_symbol_from_elf(const environment*		env,
> +lookup_symbol_from_elf(environment&			env,
>   		       Elf*				elf_handle,
>   		       const string&			symbol_name,
>   		       bool				demangle,
> @@ -1500,7 +1282,7 @@ lookup_symbol_from_elf(const environment*		env,
>   ///
>   /// @return true iff the symbol was found.
>   static bool
> -lookup_public_function_symbol_from_elf(const environment*		env,
> +lookup_public_function_symbol_from_elf(environment&			env,
>   				       Elf*				elf_handle,
>   				       const string&			symbol_name,
>   				       vector<elf_symbol_sptr>&	func_syms)
> @@ -1533,120 +1315,6 @@ lookup_public_function_symbol_from_elf(const environment*		env,
>     return found;
>   }
>   
> -/// Get data tag information of an ELF file by looking up into its
> -/// dynamic segment
> -///
> -/// @param elf the elf handle to use for the query.
> -///
> -/// @param dt_tag data tag to look for in dynamic segment
> -/// @param dt_tag_data vector of found information for a given @p data_tag
> -///
> -/// @return true iff data tag @p data_tag was found
> -
> -bool
> -lookup_data_tag_from_dynamic_segment(Elf*                       elf,
> -                                     Elf64_Sxword               data_tag,
> -                                     vector<string>&            dt_tag_data)
> -{
> -  size_t num_prog_headers = 0;
> -  bool found = false;
> -  if (elf_getphdrnum(elf, &num_prog_headers) < 0)
> -    return found;
> -
> -  // Cycle through each program header.
> -  for (size_t i = 0; i < num_prog_headers; ++i)
> -    {
> -      GElf_Phdr phdr_mem;
> -      GElf_Phdr *phdr = gelf_getphdr(elf, i, &phdr_mem);
> -      if (phdr == NULL || phdr->p_type != PT_DYNAMIC)
> -        continue;
> -
> -      // Poke at the dynamic segment like a section, so that we can
> -      // get its section header information; also we'd like to read
> -      // the data of the segment by using elf_getdata() but that
> -      // function needs a Elf_Scn data structure to act on.
> -      // Elfutils doesn't really have any particular function to
> -      // access segment data, other than the functions used to
> -      // access section data.
> -      Elf_Scn *dynamic_section = gelf_offscn(elf, phdr->p_offset);
> -      GElf_Shdr  shdr_mem;
> -      GElf_Shdr *dynamic_section_header = gelf_getshdr(dynamic_section,
> -						       &shdr_mem);
> -      if (dynamic_section_header == NULL
> -          || dynamic_section_header->sh_type != SHT_DYNAMIC)
> -        continue;
> -
> -      // Get data of the dynamic segment (seen as a section).
> -      Elf_Data *data = elf_getdata(dynamic_section, NULL);
> -      if (data == NULL)
> -        continue;
> -
> -      // Get the index of the section headers string table.
> -      size_t string_table_index = 0;
> -      ABG_ASSERT (elf_getshdrstrndx(elf, &string_table_index) >= 0);
> -
> -      size_t dynamic_section_header_entry_size = gelf_fsize(elf,
> -                                                            ELF_T_DYN, 1,
> -                                                            EV_CURRENT);
> -
> -      GElf_Shdr link_mem;
> -      GElf_Shdr *link =
> -        gelf_getshdr(elf_getscn(elf,
> -                                dynamic_section_header->sh_link),
> -		     &link_mem);
> -      ABG_ASSERT(link != NULL);
> -
> -      size_t num_dynamic_section_entries =
> -        dynamic_section_header->sh_size / dynamic_section_header_entry_size;
> -
> -      // Now walk through all the DT_* data tags that are in the
> -      // segment/section
> -      for (size_t j = 0; j < num_dynamic_section_entries; ++j)
> -        {
> -          GElf_Dyn dynamic_section_mem;
> -          GElf_Dyn *dynamic_section = gelf_getdyn(data,
> -                                                  j,
> -                                                  &dynamic_section_mem);
> -          if (dynamic_section->d_tag == data_tag)
> -            {
> -              dt_tag_data.push_back(elf_strptr(elf,
> -                                               dynamic_section_header->sh_link,
> -					       dynamic_section->d_un.d_val));
> -              found = true;
> -            }
> -        }
> -    }
> -  return found;
> -}
> -
> -/// Convert the type of ELF file into @ref elf_type.
> -///
> -/// @param elf the elf handle to use for the query.
> -///
> -/// @return the @ref elf_type for a given elf type.
> -static elf_type
> -elf_file_type(Elf* elf)
> -{
> -  GElf_Ehdr ehdr_mem;
> -  GElf_Ehdr *header = gelf_getehdr (elf, &ehdr_mem);
> -  vector<string> dt_debug_data;
> -
> -  switch (header->e_type)
> -    {
> -    case ET_DYN:
> -      if (lookup_data_tag_from_dynamic_segment(elf, DT_DEBUG, dt_debug_data))
> -	return ELF_TYPE_PI_EXEC;
> -      else
> -	return ELF_TYPE_DSO;
> -    case ET_EXEC:
> -      return ELF_TYPE_EXEC;
> -    case ET_REL:
> -      return ELF_TYPE_RELOCATABLE;
> -    default:
> -      return ELF_TYPE_UNKNOWN;
> -    }
> -}
> -
>   // ---------------------------------------
>   // <location expression evaluation types>
>   // ---------------------------------------
> @@ -2004,35 +1672,18 @@ struct dwarf_expr_eval_context
>   // </location expression evaluation types>
>   // ---------------------------------------
>   
> -/// The context used to build ABI corpus from debug info in DWARF
> -/// format.
> -///
> -/// This context is to be created by create_read_context().  It's then
> -/// passed to all the routines that read specific dwarf bits as they
> -/// get some important data from it.
> +class reader;
> +
> +typedef shared_ptr<reader> reader_sptr;
> +
> +/// The DWARF reader used to build the ABI corpus from debug info in
> +/// DWARF format.
>   ///
> -/// When a new data member is added to this context, it must be
> -/// initiliazed by the read_context::initiliaze() function.  So please
> -/// do not forget.
> -class read_context
> +/// This type is to be instanciated
> +/// abigail::dwarf_reader::reader::create().
> +class reader : public elf_based_reader
>   {
>   public:
> -  struct options_type
> -  {
> -    environment*	env;
> -    bool		load_in_linux_kernel_mode;
> -    bool		load_all_types;
> -    bool		show_stats;
> -    bool		do_log;
> -
> -    options_type()
> -      : env(),
> -	load_in_linux_kernel_mode(),
> -	load_all_types(),
> -	show_stats(),
> -	do_log()
> -    {}
> -  };// read_context::options_type
>   
>     /// A set of containers that contains one container per kind of @ref
>     /// die_source.  This allows to associate DIEs to things, depending
> @@ -2092,7 +1743,7 @@ public:
>       /// Getter for the container associated to DIEs coming from the
>       /// same source as a given DIE.
>       ///
> -    /// @param ctxt the read context to consider.
> +    /// @param rdr the DWARF reader to consider.
>       ///
>       /// @param die the DIE which should have the same source as the
>       /// source of the container we want.
> @@ -2100,16 +1751,16 @@ public:
>       /// @return the container that associates DIEs coming from the
>       /// same source as @p die.
>       ContainerType&
> -    get_container(const read_context& ctxt, const Dwarf_Die *die)
> +    get_container(const reader& rdr, const Dwarf_Die *die)
>       {
> -      const die_source source = ctxt.get_die_source(die);
> +      const die_source source = rdr.get_die_source(die);
>         return get_container(source);
>       }
>   
>       /// Getter for the container associated to DIEs coming from the
>       /// same source as a given DIE.
>       ///
> -    /// @param ctxt the read context to consider.
> +    /// @param rdr the DWARF reader to consider.
>       ///
>       /// @param die the DIE which should have the same source as the
>       /// source of the container we want.
> @@ -2117,10 +1768,10 @@ public:
>       /// @return the container that associates DIEs coming from the
>       /// same source as @p die.
>       const ContainerType&
> -    get_container(const read_context& ctxt, const Dwarf_Die *die) const
> +    get_container(const reader& rdr, const Dwarf_Die *die) const
>       {
>         return const_cast<die_source_dependant_container_set*>(this)->
> -	get_container(ctxt, die);
> +	get_container(rdr, die);
>       }
>   
>       /// Clear the container set.
> @@ -2133,28 +1784,7 @@ public:
>       }
>     }; // end die_dependant_container_set
>   
> -  suppr::suppressions_type	supprs_;
>     unsigned short		dwarf_version_;
> -  Dwfl_Callbacks		offline_callbacks_;
> -  // The set of directories under which to look for debug info.
> -  vector<char**>		debug_info_root_paths_;
> -  dwfl_sptr			handle_;
> -  Dwarf*			dwarf_;
> -  // The alternate debug info.  Alternate debug info sections are a
> -  // DWARF extension as of DWARF4 and are described at
> -  // http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.  Below are
> -  // the file desctor used to access the alternate debug info
> -  // sections, and the representation of the DWARF debug info.  Both
> -  // need to be freed after we are done using them, with fclose and
> -  // dwarf_end.
> -  int				alt_fd_;
> -  Dwarf*			alt_dwarf_;
> -  string			alt_debug_info_path_;
> -  // The address range of the offline elf file we are looking at.
> -  Dwfl_Module*			elf_module_;
> -  mutable Elf*			elf_handle_;
> -  string			elf_path_;
> -  mutable Elf_Scn*		symtab_section_;
>     Dwarf_Die*			cur_tu_die_;
>     mutable dwarf_expr_eval_context	dwarf_expr_eval_context_;
>     // A set of maps (one per kind of die source) that associates a decl
> @@ -2210,8 +1840,6 @@ public:
>     string_classes_map		decl_only_classes_map_;
>     string_enums_map		decl_only_enums_map_;
>     die_tu_map_type		die_tu_map_;
> -  corpus_group_sptr		cur_corpus_group_;
> -  corpus_sptr			cur_corpus_;
>     translation_unit_sptr	cur_tu_;
>     scope_decl_sptr		nil_scope_;
>     scope_stack_type		scope_stack_;
> @@ -2228,12 +1856,6 @@ public:
>     offset_offset_map_type	alternate_die_parent_map_;
>     offset_offset_map_type	type_section_die_parent_map_;
>     list<var_decl_sptr>		var_decls_to_add_;
> -  vector<string>		dt_needed_;
> -  string			dt_soname_;
> -  string			elf_architecture_;
> -  corpus::exported_decls_builder* exported_decls_builder_;
> -  options_type			options_;
> -  bool				drop_undefined_syms_;
>   #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
>     bool				debug_die_canonicalization_is_on_;
>     bool				use_canonical_die_comparison_;
> @@ -2242,14 +1864,11 @@ public:
>     mutable size_t		canonical_propagated_count_;
>     mutable size_t		cancelled_propagation_count_;
>   
> -  read_context();
> +protected:
>   
> -private:
> -  mutable symtab_reader::symtab_sptr symtab_;
> +  reader() = delete;
>   
> -public:
> -
> -  /// Constructor of read_context.
> +  /// Constructor of reader.
>     ///
>     /// @param elf_path the path to the elf file the context is to be
>     /// used for.
> @@ -2260,14 +1879,14 @@ public:
>     /// split file.
>     ///
>     /// @param environment the environment used by the current context.
> -  /// This environment contains resources needed by the reader and by
> +  /// This environment contains resources needed by the DWARF reader and by
>     /// the types and declarations that are to be created later.  Note
>     /// that ABI artifacts that are to be compared all need to be
>     /// created within the same environment.
>     ///
>     /// Please also note that the life time of this environment object
>     /// must be greater than the life time of the resulting @ref
> -  /// read_context the context uses resources that are allocated in
> +  /// reader the context uses resources that are allocated in
>     /// the environment.
>     ///
>     /// @param load_all_types if set to false only the types that are
> @@ -2278,36 +1897,23 @@ public:
>     /// @param linux_kernel_mode if set to true, then consider the special
>     /// linux kernel symbol tables when determining if a symbol is
>     /// exported or not.
> -  read_context(const string&	elf_path,
> -	       const vector<char**>& debug_info_root_paths,
> -	       ir::environment* environment,
> -	       bool		load_all_types,
> -	       bool		linux_kernel_mode)
> +  reader(const string&		elf_path,
> +	 const vector<char**>&	debug_info_root_paths,
> +	 environment&		environment,
> +	 bool			load_all_types,
> +	 bool			linux_kernel_mode)
> +    : elf_based_reader(elf_path,
> +		       debug_info_root_paths,
> +		       environment)
>     {
> -    initialize(elf_path, debug_info_root_paths, environment,
> -	       load_all_types, linux_kernel_mode);
> +    initialize(load_all_types, linux_kernel_mode);
>     }
>   
> -  /// Initializer of read_context.
> -  ///
> -  /// @param elf_path the path to the elf file the context is to be
> -  /// used for.
> +public:
> +
> +  /// Initializer of reader.
>     ///
> -  /// @param debug_info_root_paths a vector of pointers to the path to
> -  /// the root directory under which the debug info is to be found for
> -  /// @p elf_path.  Leave this empty if the debug info is not in a
> -  /// split file.
> -  ///
> -  /// @param environment the environment used by the current context.
> -  /// This environment contains resources needed by the reader and by
> -  /// the types and declarations that are to be created later.  Note
> -  /// that ABI artifacts that are to be compared all need to be
> -  /// created within the same environment.
> -  ///
> -  /// Please also note that the life time of this environment object
> -  /// must be greater than the life time of the resulting @ref
> -  /// read_context the context uses resources that are allocated in
> -  /// the environment.
> +  /// Resets the reader so that it can be re-used to read another binary.
>     ///
>     /// @param load_all_types if set to false only the types that are
>     /// reachable from publicly exported declarations (of functions and
> @@ -2318,27 +1924,10 @@ public:
>     /// special linux kernel symbol tables when determining if a symbol
>     /// is exported or not.
>     void
> -  initialize(const string&	elf_path,
> -	     const vector<char**>& debug_info_root_paths,
> -	     ir::environment* environment,
> -	     bool		load_all_types,
> -	     bool		linux_kernel_mode)
> +  initialize(bool load_all_types, bool linux_kernel_mode)
>     {
>       dwarf_version_ = 0;
> -    dwarf_ = 0;
> -    handle_.reset();
> -    alt_fd_ = 0;
> -    alt_dwarf_ = 0;
> -    elf_module_ = 0;
> -    elf_handle_ = 0;
> -    elf_path_ = elf_path;
> -    symtab_section_ = 0;
>       cur_tu_die_ =  0;
> -    exported_decls_builder_ = 0;
> -
> -    clear_alt_debug_info_data();
> -
> -    supprs_.clear();
>       decl_die_repr_die_offsets_maps_.clear();
>       type_die_repr_die_offsets_maps_.clear();
>       die_qualified_name_maps_.clear();
> @@ -2358,8 +1947,8 @@ public:
>       types_to_canonicalize_.clear();
>       decl_only_classes_map_.clear();
>       die_tu_map_.clear();
> -    cur_corpus_group_.reset();
> -    cur_corpus_.reset();
> +    corpus().reset();
> +    corpus_group().reset();
>       cur_tu_.reset();
>       primary_die_parent_map_.clear();
>       tu_die_imported_unit_points_map_.clear();
> @@ -2368,20 +1957,9 @@ public:
>       alternate_die_parent_map_.clear();
>       type_section_die_parent_map_.clear();
>       var_decls_to_add_.clear();
> -    dt_needed_.clear();
> -    dt_soname_.clear();
> -    elf_architecture_.clear();
> -
> -    symtab_.reset();
> -
>       clear_per_translation_unit_data();
> -
> -    memset(&offline_callbacks_, 0, sizeof(offline_callbacks_));
> -    create_default_dwfl(debug_info_root_paths);
> -    options_.env = environment;
> -    options_.load_in_linux_kernel_mode = linux_kernel_mode;
> -    options_.load_all_types = load_all_types;
> -    drop_undefined_syms_ = false;
> +    options().load_in_linux_kernel_mode = linux_kernel_mode;
> +    options().load_all_types = load_all_types;
>   #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
>       debug_die_canonicalization_is_on_ =
>         environment->debug_die_canonicalization_is_on();
> @@ -2393,27 +1971,349 @@ public:
>       load_in_linux_kernel_mode(linux_kernel_mode);
>     }
>   
> -  /// Clear the resources related to the alternate DWARF data.
> +    /// Initializer of reader.
> +  ///
> +  /// Resets the reader so that it can be re-used to read another binary.
> +  ///
> +  /// @param elf_path the path to the new ELF file.
> +  ///
> +  /// @param debug_info_root_paths the vector of debug-info path to
> +  /// look for split debug info.
> +  ///
> +  /// @param load_all_types if set to false only the types that are
> +  /// reachable from publicly exported declarations (of functions and
> +  /// variables) are read.  If set to true then all types found in the
> +  /// debug information are loaded.
> +  ///
> +  /// @param linux_kernel_mode if set to true, then consider the
> +  /// special linux kernel symbol tables when determining if a symbol
> +  /// is exported or not.
>     void
> -  clear_alt_debug_info_data()
> +  initialize(const string&		elf_path,
> +	     const vector<char**>&	debug_info_root_paths,
> +	     bool			load_all_types,
> +	     bool			linux_kernel_mode)
>     {
> -    if (alt_fd_)
> -      {
> -	close(alt_fd_);
> -	alt_fd_ = 0;
> -	if (alt_dwarf_)
> -	  {
> -	    dwarf_end(alt_dwarf_);
> -	    alt_dwarf_ = 0;
> -	  }
> -	alt_debug_info_path_.clear();
> -      }
> +    reset(elf_path, debug_info_root_paths);
> +    initialize(load_all_types, linux_kernel_mode);
> +  }
> +
> +  /// Create an instance of DWARF Reader.
> +  ///
> +  /// @param elf_path the path to the ELF file to read from.
> +  ///
> +  /// @param debug_info_root_paths a vector of paths where to look up
> +  /// split debug info files.
> +  ///
> +  /// @param environment the environment to be used by the reader.
> +  ///
> +  /// @param load_all_types if set to false only the types that are
> +  /// reachable from publicly exported declarations (of functions and
> +  /// variables) are read.  If set to true then all types found in the
> +  /// debug information are loaded.
> +  ///
> +  /// @param linux_kernel_mode if set to true, then consider the
> +  /// special linux kernel symbol tables when determining if a symbol
> +  /// is exported or not.
> +  static dwarf_reader::reader_sptr
> +  create(const std::string&	elf_path,
> +	 const vector<char**>&	debug_info_root_paths,
> +	 environment&		environment,
> +	 bool			load_all_types,
> +	 bool			linux_kernel_mode)
> +  {
> +    reader_sptr result(new reader(elf_path, debug_info_root_paths,
> +				  environment, load_all_types,
> +				  linux_kernel_mode));
> +    return result;
>     }
>   
> -  /// Detructor of the @ref read_context type.
> -  ~read_context()
> +  /// Destructor of the @ref reader type.
> +  ~reader()
>     {
> -    clear_alt_debug_info_data();
> +  }
> +
> +  /// Read and analyze the ELF and DWARF information associated with
> +  /// the underlying ELF file and build an ABI corpus out of it.
> +  ///
> +  /// @param status output parameter.  This is set to the status of
> +  /// the analysis of the debug info.
> +  ///
> +  /// @return the resulting ABI corpus.
> +  corpus_sptr
> +  read_corpus(status& status)
> +  {
> +    status = STATUS_UNKNOWN;
> +
> +    // Load the generic ELF parts of the corpus.
> +    elf_reader::reader::read_corpus(status);
> +
> +    if ((status & STATUS_NO_SYMBOLS_FOUND)
> +	|| !(status & STATUS_OK))
> +      // Either we couldn't find ELF symbols or something went badly
> +      // wrong.  There is nothing we can do with this ELF file.  Bail
> +      // out.
> +      return corpus_sptr();
> +
> +    // If we couldn't find debug info from the elf path, then say it.
> +    if (dwarf_debug_info() == nullptr)
> +      status |= STATUS_DEBUG_INFO_NOT_FOUND;
> +
> +    {
> +      string alt_di_path;
> +      if (refers_to_alt_debug_info(alt_di_path)
> +	  && !alternate_dwarf_debug_info())
> +	status |= STATUS_ALT_DEBUG_INFO_NOT_FOUND;
> +    }
> +
> +    if (// If debug info was found but not the required alternate debug
> +	// info ...
> +	((status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
> +	 && !(status & STATUS_DEBUG_INFO_NOT_FOUND)))
> +      // ... then we cannot handle the binary.
> +      return corpus_sptr();
> +
> +    // Read the variable and function descriptions from the debug info
> +    // we have, through the dwfl handle.
> +    corpus_sptr corp = read_debug_info_into_corpus();
> +
> +    status |= STATUS_OK;
> +
> +    return corp;
> +  }
> +
> +  /// Read an analyze the DWARF information.
> +  ///
> +  /// Construct an ABI corpus from it.
> +  ///
> +  /// This is a sub-routine of abigail::dwarf_reader::reader::read_corpus().
> +  ///
> +  /// @return the resulting ABI corpus.
> +  corpus_sptr
> +  read_debug_info_into_corpus()
> +  {
> +    clear_per_corpus_data();
> +
> +    // First set some mundane properties of the corpus gathered from
> +    // ELF.
> +    corpus::origin origin = corpus::DWARF_ORIGIN;
> +    if (is_linux_kernel(elf_handle()))
> +      origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
> +    corpus()->set_origin(origin);
> +
> +    if (origin & corpus::LINUX_KERNEL_BINARY_ORIGIN
> +	&& !env().user_set_analyze_exported_interfaces_only())
> +      // So we are looking at the Linux Kernel and the user has not set
> +      // any particular option regarding the amount of types to analyse.
> +      // In that case, we need to only analyze types that are reachable
> +      // from exported interfaces otherwise we get such a massive amount
> +      // of type DIEs to look at that things are just too slow down the
> +      // road.
> +      env().analyze_exported_interfaces_only(true);
> +
> +    corpus()->set_soname(dt_soname());
> +    corpus()->set_needed(dt_needed());
> +    corpus()->set_architecture_name(elf_architecture());
> +    if (corpus_group_sptr group = corpus_group())
> +      group->add_corpus(corpus());
> +
> +    // Set symbols information to the corpus.
> +    corpus()->set_symtab(symtab());
> +
> +    // Get out now if no debug info is found.
> +    if (!dwarf_debug_info())
> +      return corpus();
> +
> +    uint8_t address_size = 0;
> +    size_t header_size = 0;
> +
> +#ifdef WITH_DEBUG_SELF_COMPARISON
> +    if (env().self_comparison_debug_is_on())
> +      env().set_self_comparison_debug_input(corpus());
> +#endif
> +
> +    // Walk all the DIEs of the debug info to build a DIE -> parent map
> +    // useful for get_die_parent() to work.
> +    {
> +      tools_utils::timer t;
> +      if (do_log())
> +	{
> +	  cerr << "building die -> parent maps ...";
> +	  t.start();
> +	}
> +
> +      build_die_parent_maps();
> +
> +      if (do_log())
> +	{
> +	  t.stop();
> +	  cerr << " DONE@" << corpus()->get_path()
> +	       << ":"
> +	       << t
> +	       << "\n";
> +	}
> +    }
> +
> +    env().canonicalization_is_done(false);
> +
> +    {
> +      tools_utils::timer t;
> +      if (do_log())
> +	{
> +	  cerr << "building the libabigail internal representation ...";
> +	  t.start();
> +	}
> +      // And now walk all the DIEs again to build the libabigail IR.
> +      Dwarf_Half dwarf_vers = 0;
> +      for (Dwarf_Off offset = 0, next_offset = 0;
> +	   (dwarf_next_unit(const_cast<Dwarf*>(dwarf_debug_info()),
> +			    offset, &next_offset, &header_size,
> +			    &dwarf_vers, NULL, &address_size, NULL,
> +			    NULL, NULL) == 0);
> +	   offset = next_offset)
> +	{
> +	  Dwarf_Off die_offset = offset + header_size;
> +	  Dwarf_Die unit;
> +	  if (!dwarf_offdie(const_cast<Dwarf*>(dwarf_debug_info()),
> +			    die_offset, &unit)
> +	      || dwarf_tag(&unit) != DW_TAG_compile_unit)
> +	    continue;
> +
> +	  dwarf_version(dwarf_vers);
> +
> +	  address_size *= 8;
> +
> +	  // Build a translation_unit IR node from cu; note that cu must
> +	  // be a DW_TAG_compile_unit die.
> +	  translation_unit_sptr ir_node =
> +	    build_translation_unit_and_add_to_ir(*this, &unit, address_size);
> +	  ABG_ASSERT(ir_node);
> +	}
> +      if (do_log())
> +	{
> +	  t.stop();
> +	  cerr << " DONE@" << corpus()->get_path()
> +	       << ":"
> +	       << t
> +	       << "\n";
> +
> +	  cerr << "Number of aggregate types compared: "
> +	       << compare_count_ << "\n"
> +	       << "Number of canonical types propagated: "
> +	       << canonical_propagated_count_ << "\n"
> +	       << "Number of cancelled propagated canonical types:"
> +	       << cancelled_propagation_count_ << "\n";
> +	}
> +    }
> +
> +    {
> +      tools_utils::timer t;
> +      if (do_log())
> +	{
> +	  cerr << "resolving declaration only classes ...";
> +	  t.start();
> +	}
> +      resolve_declaration_only_classes();
> +      if (do_log())
> +	{
> +	  t.stop();
> +	  cerr << " DONE@" << corpus()->get_path()
> +	       << ":"
> +	       << t
> +	       <<"\n";
> +	}
> +    }
> +
> +    {
> +      tools_utils::timer t;
> +      if (do_log())
> +	{
> +	  cerr << "resolving declaration only enums ...";
> +	  t.start();
> +	}
> +      resolve_declaration_only_enums();
> +      if (do_log())
> +	{
> +	  t.stop();
> +	  cerr << " DONE@" << corpus()->get_path()
> +	       << ":"
> +	       << t
> +	       <<"\n";
> +	}
> +    }
> +
> +    {
> +      tools_utils::timer t;
> +      if (do_log())
> +	{
> +	  cerr << "fixing up functions with linkage name but "
> +	       << "no advertised underlying symbols ....";
> +	  t.start();
> +	}
> +      fixup_functions_with_no_symbols();
> +      if (do_log())
> +	{
> +	  t.stop();
> +	  cerr << " DONE@" << corpus()->get_path()
> +	       <<":"
> +	       << t
> +	       <<"\n";
> +	}
> +    }
> +
> +    /// Now, look at the types that needs to be canonicalized after the
> +    /// translation has been constructed (which is just now) and
> +    /// canonicalize them.
> +    ///
> +    /// These types need to be constructed at the end of the translation
> +    /// unit reading phase because some types are modified by some DIEs
> +    /// even after the principal DIE describing the type has been read;
> +    /// this happens for clones of virtual destructors (for instance) or
> +    /// even for some static data members.  We need to do that for types
> +    /// are in the alternate debug info section and for types that in
> +    /// the main debug info section.
> +    {
> +      tools_utils::timer t;
> +      if (do_log())
> +	{
> +	  cerr << "perform late type canonicalizing ...\n";
> +	  t.start();
> +	}
> +
> +      perform_late_type_canonicalizing();
> +      if (do_log())
> +	{
> +	  t.stop();
> +	  cerr << "late type canonicalizing DONE@"
> +	       << corpus()->get_path()
> +	       << ":"
> +	       << t
> +	       << "\n";
> +	}
> +    }
> +
> +    env().canonicalization_is_done(true);
> +
> +    {
> +      tools_utils::timer t;
> +      if (do_log())
> +	{
> +	  cerr << "sort functions and variables ...";
> +	  t.start();
> +	}
> +      corpus()->sort_functions();
> +      corpus()->sort_variables();
> +      if (do_log())
> +	{
> +	  t.stop();
> +	  cerr << " DONE@" << corpus()->get_path()
> +	       << ":"
> +	       << t
> +	       <<" \n";
> +	}
> +    }
> +
> +    return corpus();
>     }
>   
>     /// Clear the data that is relevant only for the current translation
> @@ -2442,23 +2342,16 @@ public:
>     /// Getter for the current environment.
>     ///
>     /// @return the current environment.
> -  const ir::environment*
> -  env() const
> -  {return options_.env;}
> +  environment&
> +  env()
> +  {return options().env;}
>   
>     /// Getter for the current environment.
>     ///
>     /// @return the current environment.
> -  ir::environment*
> -  env()
> -  {return options_.env;}
> -
> -  /// Setter for the current environment.
> -  ///
> -  /// @param env the new current environment.
> -  void
> -  env(ir::environment* env)
> -  {options_.env = env;}
> +  const environment&
> +  env() const
> +  {return const_cast<reader*>(this)->env();}
>   
>     /// Getter for the flag that tells us if we are dropping functions
>     /// and variables that have undefined symbols.
> @@ -2467,7 +2360,7 @@ public:
>     /// undefined symbols.
>     bool
>     drop_undefined_syms() const
> -  {return drop_undefined_syms_;}
> +  {return options().drop_undefined_syms;}
>   
>     /// Setter for the flag that tells us if we are dropping functions
>     /// and variables that have undefined symbols.
> @@ -2475,67 +2368,9 @@ public:
>     /// @param f the new value of the flag.
>     void
>     drop_undefined_syms(bool f)
> -  {drop_undefined_syms_ = f;}
> -
> -  /// Getter of the suppression specifications to be used during
> -  /// ELF/DWARF parsing.
> -  ///
> -  /// @return the suppression specifications.
> -  const suppr::suppressions_type&
> -  get_suppressions() const
> -  {return supprs_;}
> -
> -  /// Getter of the suppression specifications to be used during
> -  /// ELF/DWARF parsing.
> -  ///
> -  /// @return the suppression specifications.
> -  suppr::suppressions_type&
> -  get_suppressions()
> -  {return supprs_;}
> -
> -  /// Getter for the callbacks of the Dwarf Front End library of
> -  /// elfutils that is used by this reader to read dwarf.
> -  ///
> -  /// @return the callbacks.
> -  const Dwfl_Callbacks*
> -  offline_callbacks() const
> -  {return &offline_callbacks_;}
> -
> -  /// Getter for the callbacks of the Dwarf Front End library of
> -  /// elfutils that is used by this reader to read dwarf.
> -  /// @returnthe callbacks
> -  Dwfl_Callbacks*
> -  offline_callbacks()
> -  {return &offline_callbacks_;}
> -
> -  /// Constructor for a default Dwfl handle that knows how to load debug
> -  /// info from a library or executable elf file.
> -  ///
> -  /// @param debug_info_root_paths a vector of pointers to the root
> -  /// path under which to look for the debug info of the elf files
> -  /// that are later handled by the Dwfl.  This is for cases where the
> -  /// debug info is split into a different file from the binary we
> -  /// want to inspect.  On Red Hat compatible systems, this root path
> -  /// is usually /usr/lib/debug by default.  If this argument is set
> -  /// to the empty set, then "./debug" and /usr/lib/debug will be
> -  /// searched for sub-directories containing the debug info file.
> -  /// Note that for now, elfutils wants this path to be absolute
> -  /// otherwise things just don't work and the debug info is not
> -  /// found.
> -  ///
> -  /// @return the constructed Dwfl handle.
> -  void
> -  create_default_dwfl(const vector<char**>& debug_info_root_paths)
> -  {
> -    offline_callbacks()->find_debuginfo = dwfl_standard_find_debuginfo;
> -    offline_callbacks()->section_address = dwfl_offline_section_address;
> -    offline_callbacks()->debuginfo_path =
> -      debug_info_root_paths.empty() ? 0 : debug_info_root_paths.front();
> -    handle_.reset(dwfl_begin(offline_callbacks()),
> -		  dwfl_deleter());
> -    debug_info_root_paths_ = debug_info_root_paths;
> -  }
> +  {options().drop_undefined_syms = f;}
>   
> +  /// Getter of the DWARF version.
>     unsigned short
>     dwarf_version() const
>     {return dwarf_version_;}
> @@ -2544,47 +2379,9 @@ public:
>     dwarf_version(unsigned short v)
>     {dwarf_version_ = v;}
>   
> -  /// Getter for a smart pointer to a handle on the dwarf front end
> -  /// library that we use to read dwarf.
> -  ///
> -  /// @return the dwfl handle.
> -  dwfl_sptr
> -  dwfl_handle() const
> -  {return handle_;}
> -
> -  /// Setter for a smart pointer to a handle on the dwarf front end
> -  /// library that we use to read dwarf.
> -  ///
> -  /// @param h the new dwfl handle.
> -  void
> -  dwfl_handle(dwfl_sptr& h)
> -  {handle_ = h;}
> -
> -  Dwfl_Module*
> -  elf_module() const
> -  {return elf_module_;}
> -
> -  /// Return the ELF descriptor for the binary we are analizing.
> -  ///
> -  /// @return a pointer to the Elf descriptor representing the binary
> -  /// we are analizing.
> -  Elf*
> -  elf_handle() const
> -  {
> -    if (elf_handle_ == 0)
> -      {
> -	if (elf_module())
> -	  {
> -	    GElf_Addr bias = 0;
> -	    elf_handle_ = dwfl_module_getelf(elf_module(), &bias);
> -	  }
> -      }
> -    return elf_handle_;
> -  }
> -
>     /// Return the ELF descriptor used for DWARF access.
>     ///
> -  /// This can be the same as read_context::elf_handle() above, if the
> +  /// This can be the same as reader::elf_handle() above, if the
>     /// DWARF info is in the same ELF file as the one of the binary we
>     /// are analizing.  It is different if e.g, the debug info is split
>     /// from the ELF file we are analizing.
> @@ -2593,7 +2390,7 @@ public:
>     /// info.
>     Elf*
>     dwarf_elf_handle() const
> -  {return dwarf_getelf(dwarf());}
> +  {return dwarf_getelf(const_cast<Dwarf*>(dwarf_debug_info()));}
>   
>     /// Test if the debug information is in a separate ELF file wrt the
>     /// main ELF file of the program (application or shared library) we
> @@ -2606,122 +2403,24 @@ public:
>     dwarf_is_splitted() const
>     {return dwarf_elf_handle() != elf_handle();}
>   
> -  /// Add paths to the set of paths under which to look for split
> -  /// debuginfo files.
> -  ///
> -  /// @param debug_info_root_paths the paths to add.
> -  void
> -  add_debug_info_root_paths(const vector<char **>& debug_info_root_paths)
> -  {
> -    debug_info_root_paths_.insert(debug_info_root_paths_.end(),
> -				  debug_info_root_paths.begin(),
> -				  debug_info_root_paths.end());
> -  }
> -
> -  /// Add a path to the set of paths under which to look for split
> -  /// debuginfo files.
> -  ///
> -  /// @param debug_info_root_path the path to add.
> -  void
> -  add_debug_info_root_path(char** debug_info_root_path)
> -  {debug_info_root_paths_.push_back(debug_info_root_path);}
> -
> -  /// Find the alternate debuginfo file associated to a given elf file.
> -  ///
> -  /// @param elf_module represents the elf file to consider.
> -  ///
> -  /// @param alt_file_name the resulting path to the alternate
> -  /// debuginfo file found.  This is set iff the function returns a
> -  /// non-nil value.
> -  Dwarf*
> -  find_alt_debug_info(Dwfl_Module *elf_module,
> -		      string& alt_file_name,
> -		      int& alt_fd)
> -  {
> -    Dwarf *result = 0;
> -    result = dwarf_reader::find_alt_debug_info(elf_module,
> -					       debug_info_root_paths_,
> -					       alt_file_name, alt_fd);
> -    return result;
> -  }
> -
> -  /// Load the debug info associated with an elf file that is at a
> -  /// given path.
> -  ///
> -  /// @return a pointer to the DWARF debug info pointer upon
> -  /// successful debug info loading, NULL otherwise.
> -  Dwarf*
> -  load_debug_info()
> -  {
> -    if (!dwfl_handle())
> -      return 0;
> -
> -    if (dwarf_)
> -      return dwarf_;
> -
> -    elf_module_ =
> -      dwfl_report_offline(dwfl_handle().get(),
> -			  basename(const_cast<char*>(elf_path().c_str())),
> -			  elf_path().c_str(),
> -			  -1);
> -    dwfl_report_end(dwfl_handle().get(), 0, 0);
> -
> -    Dwarf_Addr bias = 0;
> -    dwarf_ = dwfl_module_getdwarf(elf_module_, &bias);
> -    // Look for split debuginfo files under multiple possible
> -    // debuginfo roots.
> -    for (vector<char**>::const_iterator i = debug_info_root_paths_.begin();
> -	 dwarf_ == 0 && i != debug_info_root_paths_.end();
> -	 ++i)
> -      {
> -	offline_callbacks()->debuginfo_path = *i;
> -	dwarf_ = dwfl_module_getdwarf(elf_module_, &bias);
> -      }
> -
> -    if (!alt_dwarf_)
> -      alt_dwarf_ = find_alt_debug_info(elf_module_,
> -				       alt_debug_info_path_,
> -				       alt_fd_);
> -
> -    return dwarf_;
> -  }
> -
> -  /// Return the main debug info we are looking at.
> -  ///
> -  /// @return the main debug info.
> -  Dwarf*
> -  dwarf() const
> -  {return dwarf_;}
> -
> -  /// Return the alternate debug info we are looking at.
> -  ///
> -  /// Note that "alternate debug info sections" is a GNU extension as
> -  /// of DWARF4 and is described at
> -  /// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1
> -  ///
> -  /// @return the alternate debug info.
> -  Dwarf*
> -  alt_dwarf() const
> -  {return alt_dwarf_;}
> -
>     /// Return the correct debug info, depending on the DIE source we
>     /// are looking at.
>     ///
>     /// @param source the DIE source to consider.
>     ///
>     /// @return the right debug info, depending on @p source.
> -  Dwarf*
> +  const Dwarf*
>     dwarf_per_die_source(die_source source) const
>     {
> -    Dwarf *result = 0;
> +    const Dwarf *result = 0;
>       switch(source)
>         {
>         case PRIMARY_DEBUG_INFO_DIE_SOURCE:
>         case TYPE_UNIT_DIE_SOURCE:
> -	result = dwarf();
> +	result = dwarf_debug_info();
>   	break;
>         case ALT_DEBUG_INFO_DIE_SOURCE:
> -	result = alt_dwarf();
> +	result = alternate_dwarf_debug_info();
>   	break;
>         case NO_DEBUG_INFO_DIE_SOURCE:
>         case NUMBER_OF_DIE_SOURCES:
> @@ -2730,25 +2429,12 @@ public:
>       return result;
>     }
>   
> -  /// Return the path to the alternate debug info as contained in the
> -  /// .gnu_debugaltlink section of the main elf file.
> -  ///
> -  /// Note that "alternate debug info sections" is a GNU extension as
> -  /// of DWARF4 and is described at
> -  /// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1
> -  ///
> -  /// @return the path to the alternate debug info file, or an empty
> -  /// path if no alternate debug info file is associated.
> -  const string&
> -  alt_debug_info_path() const
> -  {return alt_debug_info_path_;}
> -
>     /// Return the path to the ELF path we are reading.
>     ///
>     /// @return the elf path.
>     const string&
>     elf_path() const
> -  {return elf_path_;}
> +  {return corpus_path();}
>   
>     const Dwarf_Die*
>     cur_tu_die() const
> @@ -2815,9 +2501,9 @@ public:
>     {
>       offset_offset_map_type &canonical_dies =
>         die_as_type
> -      ? const_cast<read_context*>(this)->canonical_type_die_offsets_.
> +      ? const_cast<reader*>(this)->canonical_type_die_offsets_.
>         get_container(*this, die)
> -      : const_cast<read_context*>(this)->canonical_decl_die_offsets_.
> +      : const_cast<reader*>(this)->canonical_decl_die_offsets_.
>         get_container(*this, die);
>   
>       Dwarf_Die canonical_die;
> @@ -2882,13 +2568,14 @@ public:
>       // with a vector of offsets of potentially equivalent DIEs.
>       istring_dwarf_offsets_map_type& map =
>         die_as_type
> -      ? (const_cast<read_context*>(this)->
> +      ? (const_cast<reader*>(this)->
>   	 type_die_repr_die_offsets_maps().get_container(source))
> -      : (const_cast<read_context*>(this)->
> +      : (const_cast<reader*>(this)->
>   	 decl_die_repr_die_offsets_maps().get_container(source));
>   
>       Dwarf_Die die;
> -    ABG_ASSERT(dwarf_offdie(dwarf_per_die_source(source), die_offset, &die));
> +    ABG_ASSERT(dwarf_offdie(const_cast<Dwarf*>(dwarf_per_die_source(source)),
> +			    die_offset, &die));
>   
>       // The variable repr is the the string representation of 'die'.
>       //
> @@ -2963,9 +2650,9 @@ public:
>   
>       offset_offset_map_type &canonical_dies =
>         die_as_type
> -      ? const_cast<read_context*>(this)->canonical_type_die_offsets_.
> +      ? const_cast<reader*>(this)->canonical_type_die_offsets_.
>         get_container(source)
> -      : const_cast<read_context*>(this)->canonical_decl_die_offsets_.
> +      : const_cast<reader*>(this)->canonical_decl_die_offsets_.
>         get_container(source);
>   
>       Dwarf_Off die_offset = dwarf_dieoffset(const_cast<Dwarf_Die*>(die));
> @@ -2980,9 +2667,9 @@ public:
>       // with a vector of offsets of potentially equivalent DIEs.
>       istring_dwarf_offsets_map_type& map =
>         die_as_type
> -      ? (const_cast<read_context*>(this)->
> +      ? (const_cast<reader*>(this)->
>   	 type_die_repr_die_offsets_maps().get_container(*this, die))
> -      : (const_cast<read_context*>(this)->
> +      : (const_cast<reader*>(this)->
>   	 decl_die_repr_die_offsets_maps().get_container(*this, die));
>   
>       // The variable repr is the the string representation of 'die'.
> @@ -3008,7 +2695,7 @@ public:
>   	cur_die_offset = *o;
>   	get_die_from_offset(source, cur_die_offset, &canonical_die);
>   	// compare die and canonical_die.
> -	if (compare_dies_during_canonicalization(const_cast<read_context&>(*this),
> +	if (compare_dies_during_canonicalization(const_cast<reader&>(*this),
>   						 die, &canonical_die,
>   						 /*update_canonical_dies_on_the_fly=*/true))
>   	  {
> @@ -3055,9 +2742,9 @@ public:
>   
>       offset_offset_map_type &canonical_dies =
>         die_as_type
> -      ? const_cast<read_context*>(this)->canonical_type_die_offsets_.
> +      ? const_cast<reader*>(this)->canonical_type_die_offsets_.
>         get_container(source)
> -      : const_cast<read_context*>(this)->canonical_decl_die_offsets_.
> +      : const_cast<reader*>(this)->canonical_decl_die_offsets_.
>         get_container(source);
>   
>       Dwarf_Off initial_die_offset = dwarf_dieoffset(const_cast<Dwarf_Die*>(die));
> @@ -3077,9 +2764,9 @@ public:
>       // with a vector of offsets of potentially equivalent DIEs.
>       istring_dwarf_offsets_map_type& map =
>         die_as_type
> -      ? (const_cast<read_context*>(this)->
> +      ? (const_cast<reader*>(this)->
>   	 type_die_repr_die_offsets_maps().get_container(*this, die))
> -      : (const_cast<read_context*>(this)->
> +      : (const_cast<reader*>(this)->
>   	 decl_die_repr_die_offsets_maps().get_container(*this, die));
>   
>       // The variable repr is the the string representation of 'die'.
> @@ -3115,7 +2802,7 @@ public:
>   	Dwarf_Off die_offset = i->second[n];
>   	get_die_from_offset(source, die_offset, &canonical_die);
>   	// compare die and canonical_die.
> -	if (compare_dies_during_canonicalization(const_cast<read_context&>(*this),
> +	if (compare_dies_during_canonicalization(const_cast<reader&>(*this),
>   						 die, &canonical_die,
>   						 /*update_canonical_dies_on_the_fly=*/true))
>   	  {
> @@ -3198,10 +2885,10 @@ public:
>       if (tag == DW_TAG_compile_unit
>   	|| tag == DW_TAG_partial_unit)
>         {
> -	Dwarf *die_dwarf = dwarf_cu_getdwarf(cu_die.cu);
> -	if (dwarf() == die_dwarf)
> +	const Dwarf *die_dwarf = dwarf_cu_getdwarf(cu_die.cu);
> +	if (dwarf_debug_info() == die_dwarf)
>   	  source = PRIMARY_DEBUG_INFO_DIE_SOURCE;
> -	else if (alt_dwarf() == die_dwarf)
> +	else if (alternate_dwarf_debug_info() == die_dwarf)
>   	  source = ALT_DEBUG_INFO_DIE_SOURCE;
>   	else
>   	  ABG_ASSERT_NOT_REACHED;
> @@ -3226,9 +2913,11 @@ public:
>     get_die_from_offset(die_source source, Dwarf_Off offset, Dwarf_Die *die) const
>     {
>       if (source == TYPE_UNIT_DIE_SOURCE)
> -      ABG_ASSERT(dwarf_offdie_types(dwarf_per_die_source(source), offset, die));
> +      ABG_ASSERT(dwarf_offdie_types(const_cast<Dwarf*>(dwarf_per_die_source(source)),
> +				    offset, die));
>       else
> -      ABG_ASSERT(dwarf_offdie(dwarf_per_die_source(source), offset, die));
> +      ABG_ASSERT(dwarf_offdie(const_cast<Dwarf*>(dwarf_per_die_source(source)),
> +			      offset, die));
>     }
>   
>   public:
> @@ -3331,9 +3020,9 @@ public:
>   
>       if (i == map.end())
>         {
> -	read_context& ctxt  = *const_cast<read_context*>(this);
> -	string qualified_name = die_qualified_name(ctxt, die, where_offset);
> -	interned_string istr = env()->intern(qualified_name);
> +	reader& rdr  = *const_cast<reader*>(this);
> +	string qualified_name = die_qualified_name(rdr, die, where_offset);
> +	interned_string istr = env().intern(qualified_name);
>   	map[die_offset] = istr;
>   	return istr;
>         }
> @@ -3356,7 +3045,7 @@ public:
>     interned_string
>     get_die_qualified_name(Dwarf_Die *die, size_t where_offset) const
>     {
> -    return const_cast<read_context*>(this)->
> +    return const_cast<reader*>(this)->
>         get_die_qualified_name(die, where_offset);
>     }
>   
> @@ -3384,10 +3073,10 @@ public:
>   
>       // The name of the translation unit die is "".
>       if (die == cur_tu_die())
> -      return env()->intern("");
> +      return env().intern("");
>   
>       die_istring_map_type& map =
> -      die_qualified_name_maps_.get_container(*const_cast<read_context*>(this),
> +      die_qualified_name_maps_.get_container(*const_cast<reader*>(this),
>   					     die);
>   
>       size_t die_offset = dwarf_dieoffset(const_cast<Dwarf_Die*>(die));
> @@ -3396,7 +3085,7 @@ public:
>   
>       if (i == map.end())
>         {
> -	read_context& ctxt  = *const_cast<read_context*>(this);
> +	reader& rdr  = *const_cast<reader*>(this);
>   	string qualified_name;
>   	int tag = dwarf_tag(const_cast<Dwarf_Die*>(die));
>   	if ((tag == DW_TAG_structure_type
> @@ -3410,9 +3099,9 @@ public:
>   	  }
>   	else
>   	  qualified_name =
> -	    die_qualified_type_name(ctxt, die, where_offset);
> +	    die_qualified_type_name(rdr, die, where_offset);
>   
> -	interned_string istr = env()->intern(qualified_name);
> +	interned_string istr = env().intern(qualified_name);
>   	map[die_offset] = istr;
>   	return istr;
>         }
> @@ -3442,7 +3131,7 @@ public:
>     {
>       ABG_ASSERT(die);
>       die_istring_map_type& map =
> -      die_pretty_type_repr_maps_.get_container(*const_cast<read_context*>(this),
> +      die_pretty_type_repr_maps_.get_container(*const_cast<reader*>(this),
>   					       die);
>   
>       size_t die_offset = dwarf_dieoffset(const_cast<Dwarf_Die*>(die));
> @@ -3450,10 +3139,10 @@ public:
>   
>       if (i == map.end())
>         {
> -	read_context& ctxt = *const_cast<read_context*>(this);
> +	reader& rdr = *const_cast<reader*>(this);
>   	string pretty_representation =
> -	  die_pretty_print_type(ctxt, die, where_offset);
> -	interned_string istr = env()->intern(pretty_representation);
> +	  die_pretty_print_type(rdr, die, where_offset);
> +	interned_string istr = env().intern(pretty_representation);
>   	map[die_offset] = istr;
>   	return istr;
>         }
> @@ -3479,7 +3168,7 @@ public:
>       ABG_ASSERT(die);
>   
>       die_istring_map_type& map =
> -      die_pretty_repr_maps_.get_container(*const_cast<read_context*>(this),
> +      die_pretty_repr_maps_.get_container(*const_cast<reader*>(this),
>   					  die);
>   
>       size_t die_offset = dwarf_dieoffset(const_cast<Dwarf_Die*>(die));
> @@ -3487,10 +3176,10 @@ public:
>   
>       if (i == map.end())
>         {
> -	read_context& ctxt = *const_cast<read_context*>(this);
> +	reader& rdr = *const_cast<reader*>(this);
>   	string pretty_representation =
> -	  die_pretty_print(ctxt, die, where_offset);
> -	interned_string istr = env()->intern(pretty_representation);
> +	  die_pretty_print(rdr, die, where_offset);
> +	interned_string istr = env().intern(pretty_representation);
>   	map[die_offset] = istr;
>   	return istr;
>         }
> @@ -3704,7 +3393,8 @@ public:
>     odr_is_relevant(Dwarf_Off die_offset, die_source source) const
>     {
>       Dwarf_Die die;
> -    ABG_ASSERT(dwarf_offdie(dwarf_per_die_source(source), die_offset, &die));
> +    ABG_ASSERT(dwarf_offdie(const_cast<Dwarf*>(dwarf_per_die_source(source)),
> +			    die_offset, &die));
>       return odr_is_relevant(&die);
>     }
>   
> @@ -3862,9 +3552,9 @@ public:
>     {
>       offset_offset_map_type &canonical_dies =
>         die_as_type
> -      ? const_cast<read_context*>(this)->canonical_type_die_offsets_.
> +      ? const_cast<reader*>(this)->canonical_type_die_offsets_.
>         get_container(source)
> -      : const_cast<read_context*>(this)->canonical_decl_die_offsets_.
> +      : const_cast<reader*>(this)->canonical_decl_die_offsets_.
>         get_container(source);
>   
>       set_canonical_die_offset(canonical_dies,
> @@ -3932,9 +3622,9 @@ public:
>     {
>       offset_offset_map_type &canonical_dies =
>         die_as_type
> -      ? const_cast<read_context*>(this)->canonical_type_die_offsets_.
> +      ? const_cast<reader*>(this)->canonical_type_die_offsets_.
>         get_container(source)
> -      : const_cast<read_context*>(this)->canonical_decl_die_offsets_.
> +      : const_cast<reader*>(this)->canonical_decl_die_offsets_.
>         get_container(source);
>   
>       return get_canonical_die_offset(canonical_dies, die_offset);
> @@ -3958,9 +3648,9 @@ public:
>     {
>       offset_offset_map_type &canonical_dies =
>         die_as_type
> -      ? const_cast<read_context*>(this)->canonical_type_die_offsets_.
> +      ? const_cast<reader*>(this)->canonical_type_die_offsets_.
>         get_container(source)
> -      : const_cast<read_context*>(this)->canonical_decl_die_offsets_.
> +      : const_cast<reader*>(this)->canonical_decl_die_offsets_.
>         get_container(source);
>   
>       return canonical_dies.erase(die_offset);
> @@ -3999,7 +3689,7 @@ public:
>     ///
>     /// Note that the DIE must have been associated to type by a
>     /// previous invocation of the function
> -  /// read_context::associate_die_to_type().
> +  /// reader::associate_die_to_type().
>     ///
>     /// @param die the DIE to consider.
>     ///
> @@ -4020,7 +3710,7 @@ public:
>     ///
>     /// Note that the DIE must have been associated to type by a
>     /// previous invocation of the function
> -  /// read_context::associate_die_to_type().
> +  /// reader::associate_die_to_type().
>     ///
>     /// @param die_offset the offset of the DIE to consider.
>     ///
> @@ -4076,7 +3766,7 @@ public:
>     /// built.
>     const die_class_or_union_map_type&
>     die_wip_classes_map(die_source source) const
> -  {return const_cast<read_context*>(this)->die_wip_classes_map(source);}
> +  {return const_cast<reader*>(this)->die_wip_classes_map(source);}
>   
>     /// Getter of a map that associates a die that represents a
>     /// class/struct with the declaration of the class, while the class
> @@ -4113,7 +3803,7 @@ public:
>     /// @return the map of wip function types.
>     const die_function_type_map_type&
>     die_wip_function_types_map(die_source source) const
> -  {return const_cast<read_context*>(this)->die_wip_function_types_map(source);}
> +  {return const_cast<reader*>(this)->die_wip_function_types_map(source);}
>   
>     /// Getter for a map that associates a die (that represents a
>     /// function type) whith a function type, while the function type is
> @@ -4262,16 +3952,16 @@ public:
>       if (!l || !r)
>         return !!l == !!r;
>   
> -    const environment* e = l->get_environment();
> -    ABG_ASSERT(!e->canonicalization_is_done());
> +    const environment& e = l->get_environment();
> +    ABG_ASSERT(!e.canonicalization_is_done());
>   
> -    e->priv_->allow_type_comparison_results_caching(true);
> -    bool s0 = e->decl_only_class_equals_definition();
> -    e->decl_only_class_equals_definition(true);
> +    e.priv_->allow_type_comparison_results_caching(true);
> +    bool s0 = e.decl_only_class_equals_definition();
> +    e.decl_only_class_equals_definition(true);
>       bool equal = l == r;
> -    e->decl_only_class_equals_definition(s0);
> -    e->priv_->clear_type_comparison_results_cache();
> -    e->priv_->allow_type_comparison_results_caching(false);
> +    e.decl_only_class_equals_definition(s0);
> +    e.priv_->clear_type_comparison_results_cache();
> +    e.priv_->allow_type_comparison_results_caching(false);
>       return equal;
>     }
>   
> @@ -4329,7 +4019,7 @@ public:
>   	// So get the classes that might define the current
>   	// declarations which name is i->first.
>   	const type_base_wptrs_type *classes =
> -	  lookup_class_types(i->first, *current_corpus());
> +	  lookup_class_types(i->first, *corpus());
>   	if (!classes)
>   	  continue;
>   
> @@ -4565,7 +4255,7 @@ public:
>   	// So get the enums that might define the current
>   	// declarations which name is i->first.
>   	const type_base_wptrs_type *enums =
> -	  lookup_enum_types(i->first, *current_corpus());
> +	  lookup_enum_types(i->first, *corpus());
>   	if (!enums)
>   	  continue;
>   
> @@ -4694,7 +4384,7 @@ public:
>     bool
>     symbol_already_belongs_to_a_function(elf_symbol_sptr& fn)
>     {
> -    corpus_sptr corp = current_corpus();
> +    corpus_sptr corp = corpus();
>       if (!corp)
>         return false;
>   
> @@ -4732,7 +4422,7 @@ public:
>     void
>     fixup_functions_with_no_symbols()
>     {
> -    corpus_sptr corp = current_corpus();
> +    corpus_sptr corp = corpus();
>       if (!corp)
>         return;
>   
> @@ -4816,7 +4506,7 @@ public:
>   
>     /// Canonicalize types which DIE offsets are stored in vectors on
>     /// the side.  This is a sub-routine of
> -  /// read_context::perform_late_type_canonicalizing().
> +  /// reader::perform_late_type_canonicalizing().
>     ///
>     /// @param source where the DIE of the types to canonicalize are
>     /// from.
> @@ -4827,9 +4517,9 @@ public:
>       if (do_log())
>         {
>   	cerr << "going to canonicalize types";
> -	corpus_sptr c = current_corpus();
> +	corpus_sptr c = corpus();
>   	if (c)
> -	  cerr << " of corpus " << current_corpus()->get_path();
> +	  cerr << " of corpus " << corpus()->get_path();
>   	cn_timer.start();
>         }
>   
> @@ -4850,7 +4540,7 @@ public:
>   		cerr << "canonicalizing type "
>   		     << get_pretty_representation(*it, false)
>   		     << " [" << i << "/" << total << "]";
> -		if (corpus_sptr c = current_corpus())
> +		if (corpus_sptr c = corpus())
>   		  cerr << "@" << c->get_path();
>   		cerr << " ...";
>   		single_type_cn_timer.start();
> @@ -4870,9 +4560,9 @@ public:
>         {
>   	cn_timer.stop();
>   	cerr << "finished canonicalizing types";
> -	corpus_sptr c = current_corpus();
> +	corpus_sptr c = corpus();
>   	if (c)
> -	  cerr << " of corpus " << current_corpus()->get_path();
> +	  cerr << " of corpus " << corpus()->get_path();
>   	cerr << ": (" << cn_timer << ")\n";
>         }
>     }
> @@ -4948,7 +4638,7 @@ public:
>     /// @return the map.
>     const tu_die_imported_unit_points_map_type&
>     tu_die_imported_unit_points_map(die_source source) const
> -  {return const_cast<read_context*>(this)->tu_die_imported_unit_points_map(source);}
> +  {return const_cast<reader*>(this)->tu_die_imported_unit_points_map(source);}
>   
>     /// Getter for the map that associates a translation unit DIE to the
>     /// vector of imported unit points that it contains.
> @@ -4975,127 +4665,12 @@ public:
>       return tu_die_imported_unit_points_map_;
>     }
>   
> -  /// Getter of the current corpus being constructed.
> -  ///
> -  /// @return the current corpus.
> -  const corpus_sptr
> -  current_corpus() const
> -  {return cur_corpus_;}
> -
> -  /// Getter of the current corpus being constructed.
> -  ///
> -  /// @return the current corpus.
> -  corpus_sptr
> -  current_corpus()
> -  {return cur_corpus_;}
> -
> -  /// Setter of the current corpus being constructed.
> -  ///
> -  /// @param c the new corpus.
> -  void
> -  current_corpus(const corpus_sptr& c)
> -  {
> -    if (c)
> -      cur_corpus_ = c;
> -  }
> -
>     /// Reset the current corpus being constructed.
>     ///
>     /// This actually deletes the current corpus being constructed.
>     void
> -  reset_current_corpus()
> -  {cur_corpus_.reset();}
> -
> -  /// Getter of the current corpus group being constructed.
> -  ///
> -  /// @return current the current corpus being constructed, if any, or
> -  /// nil.
> -  const corpus_group_sptr
> -  current_corpus_group() const
> -  {return cur_corpus_group_;}
> -
> -  /// Getter of the current corpus group being constructed.
> -  ///
> -  /// @return current the current corpus being constructed, if any, or
> -  /// nil.
> -  corpus_group_sptr
> -  current_corpus_group()
> -  {return cur_corpus_group_;}
> -
> -  /// Setter of the current corpus group being constructed.
> -  ///
> -  /// @param g the new corpus group.
> -  void
> -  current_corpus_group(const corpus_group_sptr& g)
> -  {
> -    if (g)
> -      cur_corpus_group_ = g;
> -  }
> -
> -  /// Test if there is a corpus group being built.
> -  ///
> -  /// @return if there is a corpus group being built, false otherwise.
> -  bool
> -  has_corpus_group() const
> -  {return bool(cur_corpus_group_);}
> -
> -  /// Return the main corpus from the current corpus group, if any.
> -  ///
> -  /// @return the main corpus of the current corpus group, if any, nil
> -  /// if no corpus group is being constructed.
> -  corpus_sptr
> -  main_corpus_from_current_group()
> -  {
> -    if (cur_corpus_group_)
> -      return cur_corpus_group_->get_main_corpus();
> -    return corpus_sptr();
> -  }
> -
> -  /// Return the main corpus from the current corpus group, if any.
> -  ///
> -  /// @return the main corpus of the current corpus group, if any, nil
> -  /// if no corpus group is being constructed.
> -  const corpus_sptr
> -  main_corpus_from_current_group() const
> -  {return const_cast<read_context*>(this)->main_corpus_from_current_group();}
> -
> -  /// Test if the current corpus being built is the main corpus of the
> -  /// current corpus group.
> -  ///
> -  /// @return return true iff the current corpus being built is the
> -  /// main corpus of the current corpus group.
> -  bool
> -  current_corpus_is_main_corpus_from_current_group() const
> -  {
> -    corpus_sptr main_corpus = main_corpus_from_current_group();
> -
> -    if (main_corpus && main_corpus.get() == cur_corpus_.get())
> -      return true;
> -
> -    return false;
> -  }
> -
> -  /// Return true if the current corpus is part of a corpus group
> -  /// being built and if it's not the main corpus of the group.
> -  ///
> -  /// For instance, this would return true if we are loading a linux
> -  /// kernel *module* that is part of the current corpus group that is
> -  /// being built.  In this case, it means we should re-use types
> -  /// coming from the "vmlinux" binary that is the main corpus of the
> -  /// group.
> -  ///
> -  /// @return the corpus group the current corpus belongs to, if the
> -  /// current corpus is part of a corpus group being built. Nil otherwise.
> -  corpus_sptr
> -  should_reuse_type_from_corpus_group() const
> -  {
> -    if (has_corpus_group() && is_c_language(cur_transl_unit()->get_language()))
> -      if (corpus_sptr main_corpus = main_corpus_from_current_group())
> -	if (!current_corpus_is_main_corpus_from_current_group())
> -	  return current_corpus_group();
> -
> -    return corpus_sptr();
> -  }
> +  reset_corpus()
> +  {corpus().reset();}
>   
>     /// Get the map that associates each DIE to its parent DIE.  This is
>     /// for DIEs coming from the main debug info sections.
> @@ -5105,7 +4680,7 @@ public:
>     /// @return the DIE -> parent map.
>     const offset_offset_map_type&
>     die_parent_map(die_source source) const
> -  {return const_cast<read_context*>(this)->die_parent_map(source);}
> +  {return const_cast<reader*>(this)->die_parent_map(source);}
>   
>     /// Get the map that associates each DIE to its parent DIE.  This is
>     /// for DIEs coming from the main debug info sections.
> @@ -5210,11 +4785,7 @@ public:
>     /// @return the symbol table section if found
>     Elf_Scn*
>     find_symbol_table_section() const
> -  {
> -    if (!symtab_section_)
> -      symtab_section_ = elf_helpers::find_symbol_table_section(elf_handle());
> -    return symtab_section_;
> -  }
> +  {return find_symbol_table_section();}
>   
>     /// Lookup an elf symbol, referred to by its index, from the .symtab
>     /// section.
> @@ -5245,70 +4816,6 @@ public:
>       return true;
>     }
>   
> -  /// Test if a given function symbol has been exported.
> -  ///
> -  /// @param symbol_address the address of the symbol we are looking
> -  /// for.  Note that this address must be a relative offset from the
> -  /// beginning of the .text section, just like the kind of addresses
> -  /// that are present in the .symtab section.
> -  ///
> -  /// @returnthe elf symbol if found, or nil otherwise.
> -  elf_symbol_sptr
> -  function_symbol_is_exported(GElf_Addr symbol_address) const
> -  {
> -    elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
> -    if (!symbol)
> -      return symbol;
> -
> -    if (!symbol->is_function() || !symbol->is_public())
> -      return elf_symbol_sptr();
> -
> -    address_set_sptr set;
> -    bool looking_at_linux_kernel_binary =
> -      load_in_linux_kernel_mode() && is_linux_kernel(elf_handle());
> -
> -    if (looking_at_linux_kernel_binary)
> -      {
> -	if (symbol->is_in_ksymtab())
> -	  return symbol;
> -	return elf_symbol_sptr();
> -      }
> -
> -    return symbol;
> -  }
> -
> -  /// Test if a given variable symbol has been exported.
> -  ///
> -  /// @param symbol_address the address of the symbol we are looking
> -  /// for.  Note that this address must be a relative offset from the
> -  /// beginning of the .text section, just like the kind of addresses
> -  /// that are present in the .symtab section.
> -  ///
> -  /// @returnthe elf symbol if found, or nil otherwise.
> -  elf_symbol_sptr
> -  variable_symbol_is_exported(GElf_Addr symbol_address) const
> -  {
> -    elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
> -    if (!symbol)
> -      return symbol;
> -
> -    if (!symbol->is_variable() || !symbol->is_public())
> -      return elf_symbol_sptr();
> -
> -    address_set_sptr set;
> -    bool looking_at_linux_kernel_binary =
> -      load_in_linux_kernel_mode() && is_linux_kernel(elf_handle());
> -
> -    if (looking_at_linux_kernel_binary)
> -      {
> -	if (symbol->is_in_ksymtab())
> -	  return symbol;
> -	return elf_symbol_sptr();
> -      }
> -
> -    return symbol;
> -  }
> -
>     /// Test if a DIE represents a decl (function or variable) that has
>     /// a symbol that is exported, whatever that means.  This is
>     /// supposed to work for Linux Kernel binaries as well.
> @@ -5347,94 +4854,6 @@ public:
>       return result;
>     }
>   
> -  /// Getter for the symtab reader. Will load the symtab from the elf handle if
> -  /// not yet set.
> -  ///
> -  /// @return a shared pointer to the symtab object
> -  const symtab_reader::symtab_sptr&
> -  symtab() const
> -  {
> -    if (!symtab_)
> -      symtab_ = symtab_reader::symtab::load
> -	(elf_handle(), options_.env,
> -	 [&](const elf_symbol_sptr& symbol)
> -	 {return is_elf_symbol_suppressed(symbol);});
> -
> -    if (!symtab_)
> -      std::cerr << "Symbol table of '" << elf_path_
> -		<< "' could not be loaded\n";
> -    return symtab_;
> -  }
> -
> -  /// Getter for the ELF dt_needed tag.
> -  const vector<string>&
> -  dt_needed() const
> -  {return dt_needed_;}
> -
> -  /// Getter for the ELF dt_soname tag.
> -  const string&
> -  dt_soname() const
> -  {return dt_soname_;}
> -
> -  /// Getter for the ELF architecture of the current file.
> -  const string&
> -  elf_architecture() const
> -  {return elf_architecture_;}
> -
> -  /// Test if a given ELF symbol was suppressed by a suppression
> -  /// specification.
> -  ///
> -  /// @param symbol the ELF symbol to consider.
> -  ///
> -  /// @return true iff @p symbol is suppressed.
> -  bool
> -  is_elf_symbol_suppressed(const elf_symbol_sptr& symbol) const
> -  {
> -    return (symbol
> -	    && suppr::is_elf_symbol_suppressed(*this,
> -					       symbol->get_name(),
> -					       symbol->get_type()));
> -  }
> -
> -  /// Load the DT_NEEDED and DT_SONAME elf TAGS.
> -  ///
> -  void
> -  load_dt_soname_and_needed()
> -  {
> -    lookup_data_tag_from_dynamic_segment(elf_handle(), DT_NEEDED, dt_needed_);
> -
> -    vector<string> dt_tag_data;
> -    lookup_data_tag_from_dynamic_segment(elf_handle(), DT_SONAME, dt_tag_data);
> -    if (!dt_tag_data.empty())
> -      dt_soname_ = dt_tag_data[0];
> -  }
> -
> -  /// Read the string representing the architecture of the current ELF
> -  /// file.
> -  void
> -  load_elf_architecture()
> -  {
> -    if (!elf_handle())
> -      return;
> -
> -    GElf_Ehdr eh_mem;
> -    GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
> -
> -    elf_architecture_ = e_machine_to_string(elf_header->e_machine);
> -  }
> -
> -  /// Load various ELF data.
> -  ///
> -  /// This function loads ELF data that are not symbol maps or debug
> -  /// info.  That is, things like various tags, elf architecture and
> -  /// so on.
> -  void
> -  load_elf_properties()
> -  {
> -    load_dt_soname_and_needed();
> -    load_elf_architecture();
> -  }
> -
>     /// This is a sub-routine of maybe_adjust_fn_sym_address and
>     /// maybe_adjust_var_sym_address.
>     ///
> @@ -5660,150 +5079,13 @@ public:
>     get_variable_address(const Dwarf_Die* variable_die,
>   		       Dwarf_Addr&	address) const
>     {
> -    bool is_tls_address = false;
> -    if (!die_location_address(const_cast<Dwarf_Die*>(variable_die),
> -			      address, is_tls_address))
> -      return false;
> -    if (!is_tls_address)
> -      address = maybe_adjust_var_sym_address(address);
> -    return true;
> -  }
> -
> -  /// Tests if a suppression specification can match ABI artifacts
> -  /// coming from the binary being analyzed.
> -  ///
> -  /// This tests if the suppression can match the soname of and binary
> -  /// name of the ELF binary being analyzed.  More precisely, if there
> -  /// are any soname or file name property in the suppression and if
> -  /// those do *NOT* match the current binary, then the function
> -  /// returns false.
> -  ///
> -  /// @param s the suppression specification to consider.
> -  ///
> -  /// @return true iff either there are no soname/filename related
> -  /// property on the suppression, or if none of the soname/filename
> -  /// properties of the suppression match the current binary.
> -  bool
> -  suppression_can_match(const suppr::suppression_base& s) const
> -  {
> -    if (!s.priv_->matches_soname(dt_soname()))
> -      if (s.has_soname_related_property())
> -	// The suppression has some SONAME related properties, but
> -	// none of them match the SONAME of the current binary.  So
> -	// the suppression cannot match the current binary.
> -	return false;
> -
> -    if (!s.priv_->matches_binary_name(elf_path()))
> -      if (s.has_file_name_related_property())
> -	// The suppression has some file_name related properties, but
> -	// none of them match the file name of the current binary.  So
> -	// the suppression cannot match the current binary.
> -	return false;
> -
> -    return true;
> -  }
> -
> -  /// Test whether if a given function suppression matches a function
> -  /// designated by a regular expression that describes its linkage
> -  /// name (symbol name).
> -  ///
> -  /// @param s the suppression specification to evaluate to see if it
> -  /// matches a given function linkage name
> -  ///
> -  /// @param fn_linkage_name the linkage name of the function of interest.
> -  ///
> -  /// @return true iff the suppression specification @p s matches the
> -  /// function whose linkage name is @p fn_linkage_name.
> -  bool
> -  suppression_matches_function_sym_name(const suppr::function_suppression& s,
> -					const string& fn_linkage_name) const
> -  {
> -    if (!suppression_can_match(s))
> -      return false;
> -
> -    return suppr::suppression_matches_function_sym_name(s, fn_linkage_name);
> -  }
> -
> -  /// Test whether if a given function suppression matches a function
> -  /// designated by a regular expression that describes its name.
> -  ///
> -  /// @param s the suppression specification to evaluate to see if it
> -  /// matches a given function name.
> -  ///
> -  /// @param fn_name the name of the function of interest.  Note that
> -  /// this name must be *non* qualified.
> -  ///
> -  /// @return true iff the suppression specification @p s matches the
> -  /// function whose name is @p fn_name.
> -  bool
> -  suppression_matches_function_name(const suppr::function_suppression& s,
> -				    const string& fn_name) const
> -  {
> -    if (!suppression_can_match(s))
> -      return false;
> -
> -    return suppr::suppression_matches_function_name(s, fn_name);
> -  }
> -
> -  /// Test whether if a given variable suppression specification
> -  /// matches a variable denoted by its name.
> -  ///
> -  /// @param s the variable suppression specification to consider.
> -  ///
> -  /// @param var_name the name of the variable to consider.
> -  ///
> -  /// @return true iff the suppression specification @p s matches the
> -  /// variable whose name is @p var_name.
> -  bool
> -  suppression_matches_variable_name(const suppr::variable_suppression& s,
> -				    const string& var_name) const
> -  {
> -    if (!suppression_can_match(s))
> -      return false;
> -
> -    return suppr::suppression_matches_variable_name(s, var_name);
> -  }
> -
> -  /// Test whether if a given variable suppression specification
> -  /// matches a variable denoted by its linkage name.
> -  ///
> -  /// @param s the variable suppression specification to consider.
> -  ///
> -  /// @param var_linkage_name the linkage name of the variable to consider.
> -  ///
> -  /// @return true iff variable suppression specification @p s matches
> -  /// the variable denoted by linkage name @p var_linkage_name.
> -  bool
> -  suppression_matches_variable_sym_name(const suppr::variable_suppression& s,
> -					const string& var_linkage_name) const
> -  {
> -    if (!suppression_can_match(s))
> -      return false;
> -
> -    return suppr::suppression_matches_variable_sym_name(s, var_linkage_name);
> -  }
> -
> -  /// Test if a given type suppression specification matches a type
> -  /// designated by its name and location.
> -  ///
> -  /// @param s the suppression specification to consider.
> -  ///
> -  /// @param type_name the fully qualified type name to consider.
> -  ///
> -  /// @param type_location the type location to consider.
> -  ///
> -  /// @return true iff the type suppression specification matches a
> -  /// type of a given name and location.
> -  bool
> -  suppression_matches_type_name_or_location(const suppr::type_suppression& s,
> -					    const string& type_name,
> -					    const location& type_location) const
> -  {
> -    if (!suppression_can_match(s))
> +    bool is_tls_address = false;
> +    if (!die_location_address(const_cast<Dwarf_Die*>(variable_die),
> +			      address, is_tls_address))
>         return false;
> -
> -    return suppr::suppression_matches_type_name_or_location(s, type_name,
> -							    type_location);
> +    if (!is_tls_address)
> +      address = maybe_adjust_var_sym_address(address);
> +    return true;
>     }
>   
>     /// Getter of the exported decls builder object.
> @@ -5811,17 +5093,7 @@ public:
>     /// @return the exported decls builder.
>     corpus::exported_decls_builder*
>     exported_decls_builder()
> -  {return exported_decls_builder_;}
> -
> -  /// Setter of the exported decls builder object.
> -  ///
> -  /// Note that this @ref read_context is not responsible for the live
> -  /// time of the exported_decls_builder object.  The corpus is.
> -  ///
> -  /// @param b the new builder.
> -  void
> -  exported_decls_builder(corpus::exported_decls_builder* b)
> -  {exported_decls_builder_ = b;}
> +  {return corpus()->get_exported_decls_builder().get();}
>   
>     /// Getter of the "load_all_types" flag.  This flag tells if all the
>     /// types (including those not reachable by public declarations) are
> @@ -5830,7 +5102,7 @@ public:
>     /// @return the load_all_types flag.
>     bool
>     load_all_types() const
> -  {return options_.load_all_types;}
> +  {return options().load_all_types;}
>   
>     /// Setter of the "load_all_types" flag.  This flag tells if all the
>     /// types (including those not reachable by public declarations) are
> @@ -5839,15 +5111,15 @@ public:
>     /// @param f the new load_all_types flag.
>     void
>     load_all_types(bool f)
> -  {options_.load_all_types = f;}
> +  {options().load_all_types = f;}
>   
>     bool
>     load_in_linux_kernel_mode() const
> -  {return options_.load_in_linux_kernel_mode;}
> +  {return options().load_in_linux_kernel_mode;}
>   
>     void
>     load_in_linux_kernel_mode(bool f)
> -  {options_.load_in_linux_kernel_mode = f;}
> +  {options().load_in_linux_kernel_mode = f;}
>   
>     /// Getter of the "show_stats" flag.
>     ///
> @@ -5857,7 +5129,7 @@ public:
>     /// @return the value of the flag.
>     bool
>     show_stats() const
> -  {return options_.show_stats;}
> +  {return options().show_stats;}
>   
>     /// Setter of the "show_stats" flag.
>     ///
> @@ -5867,7 +5139,7 @@ public:
>     /// @param f the value of the flag.
>     void
>     show_stats(bool f)
> -  {options_.show_stats = f;}
> +  {options().show_stats = f;}
>   
>     /// Getter of the "do_log" flag.
>     ///
> @@ -5877,7 +5149,7 @@ public:
>     /// return the "do_log" flag.
>     bool
>     do_log() const
> -  {return options_.do_log;}
> +  {return options().do_log;}
>   
>     /// Setter of the "do_log" flag.
>     ///
> @@ -5886,35 +5158,7 @@ public:
>     /// @param f the new value of the flag.
>     void
>     do_log(bool f)
> -  {options_.do_log = f;}
> -
> -  /// If a given function decl is suitable for the set of exported
> -  /// functions of the current corpus, this function adds it to that
> -  /// set.
> -  ///
> -  /// @param fn the function to consider for inclusion into the set of
> -  /// exported functions of the current corpus.
> -  void
> -  maybe_add_fn_to_exported_decls(function_decl* fn)
> -  {
> -    if (fn)
> -      if (corpus::exported_decls_builder* b = exported_decls_builder())
> -	b->maybe_add_fn_to_exported_fns(fn);
> -  }
> -
> -  /// If a given variable decl is suitable for the set of exported
> -  /// variables of the current corpus, this variable adds it to that
> -  /// set.
> -  ///
> -  /// @param fn the variable to consider for inclusion into the set of
> -  /// exported variables of the current corpus.
> -  void
> -  maybe_add_var_to_exported_decls(var_decl* var)
> -  {
> -    if (var)
> -      if (corpus::exported_decls_builder* b = exported_decls_builder())
> -	b->maybe_add_var_to_exported_vars(var);
> -  }
> +  {options().do_log = f;}
>   
>     /// Walk the DIEs under a given die and for each child, populate the
>     /// die -> parent map to record the child -> parent relationship
> @@ -6047,13 +5291,15 @@ public:
>       // the global namespace so we don't need to build the DIE ->
>       // parent map.  So we dont build it in that case.
>       for (Dwarf_Off offset = 0, next_offset = 0;
> -	 (dwarf_next_unit(dwarf(), offset, &next_offset, &header_size,
> +	 (dwarf_next_unit(const_cast<Dwarf*>(dwarf_debug_info()),
> +			  offset, &next_offset, &header_size,
>   			  NULL, NULL, &address_size, NULL, NULL, NULL) == 0);
>   	 offset = next_offset)
>         {
>   	Dwarf_Off die_offset = offset + header_size;
>   	Dwarf_Die cu;
> -	if (!dwarf_offdie(dwarf(), die_offset, &cu))
> +	if (!dwarf_offdie(const_cast<Dwarf*>(dwarf_debug_info()),
> +			  die_offset, &cu))
>   	  continue;
>   
>   	uint64_t l = 0;
> @@ -6070,13 +5316,15 @@ public:
>       // .debug_info section in the alternate debug info file.
>       die_source source = ALT_DEBUG_INFO_DIE_SOURCE;
>       for (Dwarf_Off offset = 0, next_offset = 0;
> -	 (dwarf_next_unit(alt_dwarf(), offset, &next_offset, &header_size,
> +	 (dwarf_next_unit(const_cast<Dwarf*>(alternate_dwarf_debug_info()),
> +			  offset, &next_offset, &header_size,
>   			  NULL, NULL, &address_size, NULL, NULL, NULL) == 0);
>   	 offset = next_offset)
>         {
>   	Dwarf_Off die_offset = offset + header_size;
>   	Dwarf_Die cu;
> -	if (!dwarf_offdie(alt_dwarf(), die_offset, &cu))
> +	if (!dwarf_offdie(const_cast<Dwarf*>(alternate_dwarf_debug_info()),
> +			  die_offset, &cu))
>   	  continue;
>   	cur_tu_die(&cu);
>   
> @@ -6092,13 +5340,15 @@ public:
>       address_size = 0;
>       header_size = 0;
>       for (Dwarf_Off offset = 0, next_offset = 0;
> -	 (dwarf_next_unit(dwarf(), offset, &next_offset, &header_size,
> +	 (dwarf_next_unit(const_cast<Dwarf*>(dwarf_debug_info()),
> +			  offset, &next_offset, &header_size,
>   			  NULL, NULL, &address_size, NULL, NULL, NULL) == 0);
>   	 offset = next_offset)
>         {
>   	Dwarf_Off die_offset = offset + header_size;
>   	Dwarf_Die cu;
> -	if (!dwarf_offdie(dwarf(), die_offset, &cu))
> +	if (!dwarf_offdie(const_cast<Dwarf*>(dwarf_debug_info()),
> +			  die_offset, &cu))
>   	  continue;
>   	cur_tu_die(&cu);
>   	imported_unit_points_type& imported_units =
> @@ -6115,7 +5365,8 @@ public:
>       uint64_t type_signature = 0;
>       Dwarf_Off type_offset;
>       for (Dwarf_Off offset = 0, next_offset = 0;
> -	 (dwarf_next_unit(dwarf(), offset, &next_offset, &header_size,
> +	 (dwarf_next_unit(const_cast<Dwarf*>(dwarf_debug_info()),
> +			  offset, &next_offset, &header_size,
>   			  NULL, NULL, &address_size, NULL,
>   			  &type_signature, &type_offset) == 0);
>   	 offset = next_offset)
> @@ -6123,7 +5374,8 @@ public:
>   	Dwarf_Off die_offset = offset + header_size;
>   	Dwarf_Die cu;
>   
> -	if (!dwarf_offdie_types(dwarf(), die_offset, &cu))
> +	if (!dwarf_offdie_types(const_cast<Dwarf*>(dwarf_debug_info()),
> +				die_offset, &cu))
>   	  continue;
>   	cur_tu_die(&cu);
>   	imported_unit_points_type& imported_units =
> @@ -6132,7 +5384,7 @@ public:
>   	build_die_parent_relations_under(&cu, source, imported_units);
>         }
>     }
> -};// end class read_context.
> +};// end class reader.
>   
>   /// The type of the aggregates being compared during a DIE comparison.
>   ///
> @@ -6146,8 +5398,8 @@ public:
>   /// that takes place during the canonicalization
>   struct offset_pairs_stack_type
>   {
> -  // The DWARF read context that is useful for so many things.
> -  const read_context& ctxt_;
> +  // The DWARF DWARF reader that is useful for so many things.
> +  const reader& rdr_;
>     // The set of types that are being compared.  This is to speed up
>     // searches.
>     offset_pair_set_type set_;
> @@ -6161,8 +5413,8 @@ struct offset_pairs_stack_type
>     // types it depends on.
>     offset_pair_vect_map_type dependant_types_;
>   
> -  offset_pairs_stack_type(const read_context& ctxt)
> -    : ctxt_ (ctxt)
> +  offset_pairs_stack_type(const reader& rdr)
> +    : rdr_ (rdr)
>     {}
>   
>     /// Add a pair of types being compared to the stack of aggregates
> @@ -6377,13 +5629,13 @@ struct offset_pairs_stack_type
>   	    if (dependant_types_it->second.empty())
>   	      {
>   		if (erase_cached_results)
> -		  ctxt_.die_comparison_results_.erase(dependant_type);
> +		  rdr_.die_comparison_results_.erase(dependant_type);
>   		dependant_types_.erase(dependant_types_it);
>   	      }
>   	  }
>         }
>       if (erase_cached_results)
> -      ctxt_.die_comparison_results_.erase(p);
> +      rdr_.die_comparison_results_.erase(p);
>       redundant_types_.erase(p);
>     }
>   
> @@ -6414,32 +5666,32 @@ struct offset_pairs_stack_type
>         {
>   	// If this dependant type was canonical-type-propagated then
>   	// erase that canonical type.
> -	if (ctxt_.propagated_types_.find(dependant_type)
> -	    != ctxt_.propagated_types_.end())
> +	if (rdr_.propagated_types_.find(dependant_type)
> +	    != rdr_.propagated_types_.end())
>   	  {
> -	    ctxt_.erase_canonical_die_offset(dependant_type.first.offset_,
> +	    rdr_.erase_canonical_die_offset(dependant_type.first.offset_,
>   					     dependant_type.first.source_,
>   					     /*die_as_type=*/true);
> -	    ctxt_.propagated_types_.erase(dependant_type);
> -	    ctxt_.cancelled_propagation_count_++;
> +	    rdr_.propagated_types_.erase(dependant_type);
> +	    rdr_.cancelled_propagation_count_++;
>   	  }
>   	// Update the cached result.  We know the comparison result
>   	// must now be different.
> -	auto comp_result_it = ctxt_.die_comparison_results_.find(p);
> -	if (comp_result_it != ctxt_.die_comparison_results_.end())
> +	auto comp_result_it = rdr_.die_comparison_results_.find(p);
> +	if (comp_result_it != rdr_.die_comparison_results_.end())
>   	  {
>   	    ABG_ASSERT(comp_result_it->second == COMPARISON_RESULT_UNKNOWN);
>   	    comp_result_it->second= COMPARISON_RESULT_DIFFERENT;
>   	  }
>         }
>   
> -    if (ctxt_.propagated_types_.find(p) != ctxt_.propagated_types_.end())
> +    if (rdr_.propagated_types_.find(p) != rdr_.propagated_types_.end())
>         {
> -	ctxt_.erase_canonical_die_offset(p.first.offset_,
> +	rdr_.erase_canonical_die_offset(p.first.offset_,
>   					 p.first.source_,
>   					 /*die_as_type=*/true);
> -	ctxt_.propagated_types_.erase(p);
> -	ctxt_.cancelled_propagation_count_++;
> +	rdr_.propagated_types_.erase(p);
> +	rdr_.cancelled_propagation_count_++;
>         }
>     }
>   
> @@ -6477,7 +5729,7 @@ struct offset_pairs_stack_type
>   }; // end struct offset_pairs_stack_type
>   
>   static type_or_decl_base_sptr
> -build_ir_node_from_die(read_context&	ctxt,
> +build_ir_node_from_die(reader&	rdr,
>   		       Dwarf_Die*	die,
>   		       scope_decl*	scope,
>   		       bool		called_from_public_decl,
> @@ -6486,13 +5738,13 @@ build_ir_node_from_die(read_context&	ctxt,
>   		       bool		is_required_decl_spec = false);
>   
>   static type_or_decl_base_sptr
> -build_ir_node_from_die(read_context&	ctxt,
> +build_ir_node_from_die(reader&	rdr,
>   		       Dwarf_Die*	die,
>   		       bool		called_from_public_decl,
>   		       size_t		where_offset);
>   
>   static class_decl_sptr
> -add_or_update_class_type(read_context&	 ctxt,
> +add_or_update_class_type(reader&	 rdr,
>   			 Dwarf_Die*	 die,
>   			 scope_decl*	 scope,
>   			 bool		 is_struct,
> @@ -6502,7 +5754,7 @@ add_or_update_class_type(read_context&	 ctxt,
>   			 bool		 is_declaration_only);
>   
>   static union_decl_sptr
> -add_or_update_union_type(read_context&	 ctxt,
> +add_or_update_union_type(reader&	 rdr,
>   			 Dwarf_Die*	 die,
>   			 scope_decl*	 scope,
>   			 union_decl_sptr union_type,
> @@ -6511,25 +5763,25 @@ add_or_update_union_type(read_context&	 ctxt,
>   			 bool		 is_declaration_only);
>   
>   static decl_base_sptr
> -build_ir_node_for_void_type(read_context& ctxt);
> +build_ir_node_for_void_type(reader& rdr);
>   
>   static decl_base_sptr
> -build_ir_node_for_variadic_parameter_type(read_context &ctxt);
> +build_ir_node_for_variadic_parameter_type(reader &rdr);
>   
>   static function_decl_sptr
> -build_function_decl(read_context&	ctxt,
> +build_function_decl(reader&	rdr,
>   		    Dwarf_Die*		die,
>   		    size_t		where_offset,
>   		    function_decl_sptr	fn);
>   
>   static bool
> -function_is_suppressed(const read_context& ctxt,
> +function_is_suppressed(const reader& rdr,
>   		       const scope_decl* scope,
>   		       Dwarf_Die *function_die,
>   		       bool is_declaration_only);
>   
>   static function_decl_sptr
> -build_or_get_fn_decl_if_not_suppressed(read_context&	ctxt,
> +build_or_get_fn_decl_if_not_suppressed(reader&	rdr,
>   				       scope_decl	*scope,
>   				       Dwarf_Die	*die,
>   				       size_t	where_offset,
> @@ -6537,20 +5789,20 @@ build_or_get_fn_decl_if_not_suppressed(read_context&	ctxt,
>   				       function_decl_sptr f);
>   
>   static var_decl_sptr
> -build_var_decl(read_context&	ctxt,
> +build_var_decl(reader&	rdr,
>   	       Dwarf_Die	*die,
>   	       size_t		where_offset,
>   	       var_decl_sptr	result = var_decl_sptr());
>   
>   static var_decl_sptr
> -build_or_get_var_decl_if_not_suppressed(read_context&	ctxt,
> +build_or_get_var_decl_if_not_suppressed(reader&	rdr,
>   					scope_decl	*scope,
>   					Dwarf_Die	*die,
>   					size_t	where_offset,
>   					var_decl_sptr	res = var_decl_sptr(),
>   					bool is_required_decl_spec = false);
>   static bool
> -variable_is_suppressed(const read_context& ctxt,
> +variable_is_suppressed(const reader& rdr,
>   		       const scope_decl* scope,
>   		       Dwarf_Die *variable_die,
>   		       bool is_required_decl_spec = false);
> @@ -6559,78 +5811,7 @@ static void
>   finish_member_function_reading(Dwarf_Die*			die,
>   			       const function_decl_sptr&	f,
>   			       const class_or_union_sptr	klass,
> -			       read_context&			ctxt);
> -
> -/// Setter of the debug info root path for a dwarf reader context.
> -///
> -/// @param ctxt the dwarf reader context to consider.
> -///
> -/// @param path the new debug info root path.  This must be a pointer to a
> -/// character string which life time should be greater than the life
> -/// time of the read context.
> -void
> -set_debug_info_root_path(read_context& ctxt, char** path)
> -{ctxt.offline_callbacks()->debuginfo_path = path;}
> -
> -/// Setter of the debug info root path for a dwarf reader context.
> -///
> -/// @param ctxt the dwarf reader context to consider.
> -///
> -/// @return a pointer to the debug info root path.
> -///
> -/// time of the read context.
> -char**
> -get_debug_info_root_path(read_context& ctxt)
> -{return ctxt.offline_callbacks()->debuginfo_path;}
> -
> -/// Getter of the "show_stats" flag.
> -///
> -/// This flag tells if we should emit statistics about various
> -/// internal stuff.
> -///
> -/// @param ctx the read context to consider for this flag.
> -///
> -/// @return the value of the flag.
> -bool
> -get_show_stats(read_context& ctxt)
> -{return ctxt.show_stats();}
> -
> -/// Setter of the "show_stats" flag.
> -///
> -/// This flag tells if we should emit statistics about various
> -/// internal stuff.
> -///
> -/// @param ctxt the read context to consider for this flag.
> -///
> -/// @param f the value of the flag.
> -void
> -set_show_stats(read_context& ctxt, bool f)
> -{ctxt.show_stats(f);}
> -
> -/// Setter of the "drop_undefined_syms" flag.
> -///
> -/// This flag tells if we should drop functions or variables
> -/// with undefined symbols.
> -///
> -/// @param ctxt the read context to consider for this flag.
> -///
> -/// @param f the value of the flag.
> -void
> -set_drop_undefined_syms(read_context& ctxt, bool f)
> -{ctxt.drop_undefined_syms(f);}
> -
> -/// Setter of the "do_log" flag.
> -///
> -/// This flag tells if we should emit verbose logs for various
> -/// internal things related to DWARF reading.
> -///
> -/// @param ctxt the DWARF reading context to consider.
> -///
> -/// @param f the new value of the flag.
> -void
> -set_do_log(read_context& ctxt, bool f)
> -{ctxt.do_log(f);}
> -
> +			       reader&			rdr);
>   
>   /// Test if a given DIE is anonymous
>   ///
> @@ -6980,13 +6161,13 @@ die_address_attribute(Dwarf_Die* die, unsigned attr_name, Dwarf_Addr& result)
>   
>   /// Returns the source location associated with a decl DIE.
>   ///
> -/// @param ctxt the @ref read_context to use.
> +/// @param rdr the @ref reader to use.
>   ///
>   /// @param die the DIE the read the source location from.
>   ///
>   /// @return the location associated with @p die.
>   static location
> -die_location(const read_context& ctxt, const Dwarf_Die* die)
> +die_location(const reader& rdr, const Dwarf_Die* die)
>   {
>     if (!die)
>       return location();
> @@ -6997,7 +6178,7 @@ die_location(const read_context& ctxt, const Dwarf_Die* die)
>   
>     if (!file.empty() && line != 0)
>       {
> -      translation_unit_sptr tu = ctxt.cur_transl_unit();
> +      translation_unit_sptr tu = rdr.cur_transl_unit();
>         location l = tu->get_loc_mgr().create_new_location(file, line, 1);
>         return l;
>       }
> @@ -7018,7 +6199,7 @@ die_name(const Dwarf_Die* die)
>   
>   /// Return the location, the name and the mangled name of a given DIE.
>   ///
> -/// @param ctxt the read context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @param die the DIE to read location and names from.
>   ///
> @@ -7028,13 +6209,13 @@ die_name(const Dwarf_Die* die)
>   ///
>   /// @param linkage_name the linkage_name output parameter to set.
>   static void
> -die_loc_and_name(const read_context&	ctxt,
> +die_loc_and_name(const reader&	rdr,
>   		 Dwarf_Die*		die,
>   		 location&		loc,
>   		 string&		name,
>   		 string&		linkage_name)
>   {
> -  loc = die_location(ctxt, die);
> +  loc = die_location(rdr, die);
>     name = die_name(die);
>     linkage_name = die_linkage_name(die);
>   }
> @@ -7150,7 +6331,7 @@ die_is_public_decl(const Dwarf_Die* die)
>   /// @return true iff either the DIE is public or is a variable DIE
>   /// that is at (global) namespace level.
>   static bool
> -die_is_effectively_public_decl(const read_context& ctxt,
> +die_is_effectively_public_decl(const reader& rdr,
>   			       const Dwarf_Die* die)
>   {
>     if (die_is_public_decl(die))
> @@ -7162,7 +6343,7 @@ die_is_effectively_public_decl(const read_context& ctxt,
>         // The DIE is a variable.
>         Dwarf_Die parent_die;
>         size_t where_offset = 0;
> -      if (!get_parent_die(ctxt, die, parent_die, where_offset))
> +      if (!get_parent_die(rdr, die, parent_die, where_offset))
>   	return false;
>   
>         tag = dwarf_tag(&parent_die);
> @@ -7402,7 +6583,7 @@ type_comparison_result_to_be_cached(unsigned tag)
>   
>   /// Cache the result of comparing to type DIEs.
>   ///
> -/// @param ctxt the context to consider.
> +/// @param rdr the context to consider.
>   ///
>   /// @param tag the tag of the DIEs to consider.
>   ///
> @@ -7410,7 +6591,7 @@ type_comparison_result_to_be_cached(unsigned tag)
>   ///
>   /// @param result the comparison result to be cached.
>   static bool
> -maybe_cache_type_comparison_result(const read_context& ctxt,
> +maybe_cache_type_comparison_result(const reader& rdr,
>   				   int tag,
>   				   const offset_pair_type& p,
>   				   comparison_result result)
> @@ -7420,7 +6601,7 @@ maybe_cache_type_comparison_result(const read_context& ctxt,
>   	  && result != COMPARISON_RESULT_DIFFERENT))
>       return false;
>   
> -  ctxt.die_comparison_results_[p] = result;
> +  rdr.die_comparison_results_[p] = result;
>   
>     return true;
>   
> @@ -7428,7 +6609,7 @@ maybe_cache_type_comparison_result(const read_context& ctxt,
>   
>   /// Get the cached result of the comparison of a pair of DIEs.
>   ///
> -/// @param ctxt the context to consider.
> +/// @param rdr the context to consider.
>   ///
>   /// @param tag the tag of the pair of DIEs to consider.
>   ///
> @@ -7440,12 +6621,12 @@ maybe_cache_type_comparison_result(const read_context& ctxt,
>   /// @return true iff a cached result for the comparisonof @p has been
>   /// found and set into @p result.
>   static bool
> -get_cached_type_comparison_result(const read_context& ctxt,
> +get_cached_type_comparison_result(const reader& rdr,
>   				  const offset_pair_type& p,
>   				  comparison_result& result)
>   {
> -  auto i = ctxt.die_comparison_results_.find(p);
> -  if (i != ctxt.die_comparison_results_.end())
> +  auto i = rdr.die_comparison_results_.find(p);
> +  if (i != rdr.die_comparison_results_.end())
>       {
>         result = i->second;
>         return true;
> @@ -7456,7 +6637,7 @@ get_cached_type_comparison_result(const read_context& ctxt,
>   /// Get the cached result of the comparison of a pair of DIEs, if the
>   /// kind of DIEs ought to have its comparison results cached.
>   ///
> -/// @param ctxt the context to consider.
> +/// @param rdr the context to consider.
>   ///
>   /// @param tag the tag of the pair of DIEs to consider.
>   ///
> @@ -7468,7 +6649,7 @@ get_cached_type_comparison_result(const read_context& ctxt,
>   /// @return true iff a cached result for the comparisonof @p has been
>   /// found and set into @p result.
>   static bool
> -maybe_get_cached_type_comparison_result(const read_context& ctxt,
> +maybe_get_cached_type_comparison_result(const reader& rdr,
>   					int tag,
>   					const offset_pair_type& p,
>   					comparison_result& result)
> @@ -7478,7 +6659,7 @@ maybe_get_cached_type_comparison_result(const read_context& ctxt,
>         // Types of this kind might have their comparison result cached
>         // when they are not canonicalized.  So let's see if we have a
>         // cached comparison result.
> -      if (get_cached_type_comparison_result(ctxt, p, result))
> +      if (get_cached_type_comparison_result(rdr, p, result))
>   	return true;
>       }
>     return false;
> @@ -7878,7 +7059,7 @@ die_object_pointer_is_for_const_method(Dwarf_Die* die)
>   
>   /// Test if a DIE represents an entity that is at class scope.
>   ///
> -/// @param ctxt the read context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @param die the DIE to consider.
>   ///
> @@ -7892,12 +7073,12 @@ die_object_pointer_is_for_const_method(Dwarf_Die* die)
>   /// class_scope_die is set to the DIE of the class that contains @p
>   /// die.
>   static bool
> -die_is_at_class_scope(const read_context& ctxt,
> +die_is_at_class_scope(const reader& rdr,
>   		      const Dwarf_Die* die,
>   		      size_t where_offset,
>   		      Dwarf_Die& class_scope_die)
>   {
> -  if (!get_scope_die(ctxt, die, where_offset, class_scope_die))
> +  if (!get_scope_die(rdr, die, where_offset, class_scope_die))
>       return false;
>   
>     int tag = dwarf_tag(&class_scope_die);
> @@ -8028,7 +7209,7 @@ die_peel_pointer_and_typedef(const Dwarf_Die *die, Dwarf_Die& peeled_die)
>   
>   /// Test if a DIE for a function type represents a method type.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the DWARF reader.
>   ///
>   /// @param die the DIE to consider.
>   ///
> @@ -8049,7 +7230,7 @@ die_peel_pointer_and_typedef(const Dwarf_Die *die, Dwarf_Die& peeled_die)
>   ///
>   /// @return true iff @p die is a DIE for a method type.
>   static bool
> -die_function_type_is_method_type(const read_context& ctxt,
> +die_function_type_is_method_type(const reader& rdr,
>   				 const Dwarf_Die *die,
>   				 size_t where_offset,
>   				 Dwarf_Die& object_pointer_die,
> @@ -8077,7 +7258,7 @@ die_function_type_is_method_type(const read_context& ctxt,
>   	    has_object_pointer = true;
>   	  else
>   	    {
> -	      if (die_is_at_class_scope(ctxt, &spec_or_origin_die,
> +	      if (die_is_at_class_scope(rdr, &spec_or_origin_die,
>   					where_offset, class_die))
>   		is_static = true;
>   	      else
> @@ -8090,7 +7271,7 @@ die_function_type_is_method_type(const read_context& ctxt,
>   	    has_object_pointer = true;
>   	  else
>   	    {
> -	      if (die_is_at_class_scope(ctxt, die, where_offset, class_die))
> +	      if (die_is_at_class_scope(rdr, die, where_offset, class_die))
>   		is_static = true;
>   	      else
>   		return false;
> @@ -9441,14 +8622,14 @@ die_constant_data_member_location(const Dwarf_Die *die,
>   ///     the offset of the function in the vtable.  In this case this
>   ///     function returns that constant.
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param die the DIE to read the information from.
>   ///
>   /// @param offset the resulting constant offset, in bits.  This
>   /// argument is set iff the function returns true.
>   static bool
> -die_member_offset(const read_context& ctxt,
> +die_member_offset(const reader& rdr,
>   		  const Dwarf_Die* die,
>   		  int64_t& offset)
>   {
> @@ -9489,7 +8670,7 @@ die_member_offset(const read_context& ctxt,
>   	  bool is_tls_address = false;
>   	  if (!eval_last_constant_dwarf_sub_expr(expr, expr_len,
>   						 offset, is_tls_address,
> -						 ctxt.dwarf_expr_eval_ctxt()))
> +						 rdr.dwarf_expr_eval_ctxt()))
>   	    return false;
>   	}
>       }
> @@ -9506,7 +8687,7 @@ die_member_offset(const read_context& ctxt,
>     // offset of the bitfield data member it describes.  For details
>     // about the conversion, please read the extensive comments of
>     // read_and_convert_DW_at_bit_offset.
> -  bool is_big_endian = architecture_is_big_endian(ctxt.elf_handle());
> +  bool is_big_endian = architecture_is_big_endian(rdr.elf_handle());
>     if (read_and_convert_DW_at_bit_offset(die, is_big_endian, bit_offset))
>       offset += bit_offset;
>   
> @@ -9725,7 +8906,7 @@ get_internal_anonymous_die_name(Dwarf_Die *die,
>   /// For instance, if the DIE tag is DW_TAG_subprogram then this
>   /// function computes the name of the function *type*.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the DWARF reader.
>   ///
>   /// @param die the DIE to consider.
>   ///
> @@ -9734,7 +8915,7 @@ get_internal_anonymous_die_name(Dwarf_Die *die,
>   ///
>   /// @return a copy of the qualified name of the type.
>   static string
> -die_qualified_type_name(const read_context& ctxt,
> +die_qualified_type_name(const reader& rdr,
>   			const Dwarf_Die* die,
>   			size_t where_offset)
>   {
> @@ -9750,10 +8931,10 @@ die_qualified_type_name(const read_context& ctxt,
>     string name = die_name(die);
>   
>     Dwarf_Die scope_die;
> -  if (!get_scope_die(ctxt, die, where_offset, scope_die))
> +  if (!get_scope_die(rdr, die, where_offset, scope_die))
>       return "";
>   
> -  string parent_name = die_qualified_name(ctxt, &scope_die, where_offset);
> +  string parent_name = die_qualified_name(rdr, &scope_die, where_offset);
>     bool colon_colon = die_is_type(die) || die_is_namespace(die);
>     string separator = colon_colon ? "::" : ".";
>   
> @@ -9836,7 +9017,7 @@ die_qualified_type_name(const read_context& ctxt,
>   	string underlying_type_repr;
>   	if (has_underlying_type_die)
>   	  underlying_type_repr =
> -	    die_qualified_type_name(ctxt, &underlying_type_die, where_offset);
> +	    die_qualified_type_name(rdr, &underlying_type_die, where_offset);
>   	else
>   	  underlying_type_repr = "void";
>   
> @@ -9869,7 +9050,7 @@ die_qualified_type_name(const read_context& ctxt,
>   	  break;
>   
>   	string pointed_type_repr =
> -	  die_qualified_type_name(ctxt, &pointed_to_type_die, where_offset);
> +	  die_qualified_type_name(rdr, &pointed_to_type_die, where_offset);
>   
>   	repr = pointed_type_repr;
>   	if (repr.empty())
> @@ -9899,7 +9080,7 @@ die_qualified_type_name(const read_context& ctxt,
>   	// the ::as_string() method of that type.  So we don't add
>   	// that type to the current type tree being built.
>   	array_type_def::subrange_sptr s =
> -	  build_subrange_type(const_cast<read_context&>(ctxt),
> +	  build_subrange_type(const_cast<reader&>(rdr),
>   			      die, where_offset,
>   			      /*associate_die_to_type=*/false);
>   	repr += s->as_string();
> @@ -9912,12 +9093,12 @@ die_qualified_type_name(const read_context& ctxt,
>   	if (!die_die_attribute(die, DW_AT_type, element_type_die))
>   	  break;
>   	string element_type_name =
> -	  die_qualified_type_name(ctxt, &element_type_die, where_offset);
> +	  die_qualified_type_name(rdr, &element_type_die, where_offset);
>   	if (element_type_name.empty())
>   	  break;
>   
>   	array_type_def::subranges_type subranges;
> -	build_subranges_from_array_type_die(const_cast<read_context&>(ctxt),
> +	build_subranges_from_array_type_die(const_cast<reader&>(rdr),
>   					    die, subranges, where_offset,
>   					    /*associate_type_to_die=*/false);
>   
> @@ -9935,7 +9116,7 @@ die_qualified_type_name(const read_context& ctxt,
>   	bool is_const = false;
>   	bool is_static = false;
>   
> -	die_return_and_parm_names_from_fn_type_die(ctxt, die, where_offset,
> +	die_return_and_parm_names_from_fn_type_die(rdr, die, where_offset,
>   						   /*pretty_print=*/true,
>   						   return_type_name, class_name,
>   						   parm_names, is_const,
> @@ -9985,7 +9166,7 @@ die_qualified_type_name(const read_context& ctxt,
>   /// For instance, for a DIE of tag DW_TAG_subprogram this function
>   /// computes the signature of the function *declaration*.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the DWARF reader.
>   ///
>   /// @param die the DIE to consider.
>   ///
> @@ -9993,7 +9174,7 @@ die_qualified_type_name(const read_context& ctxt,
>   ///
>   /// @return a copy of the computed name.
>   static string
> -die_qualified_decl_name(const read_context& ctxt,
> +die_qualified_decl_name(const reader& rdr,
>   			const Dwarf_Die* die,
>   			size_t where_offset)
>   {
> @@ -10003,10 +9184,10 @@ die_qualified_decl_name(const read_context& ctxt,
>     string name = die_name(die);
>   
>     Dwarf_Die scope_die;
> -  if (!get_scope_die(ctxt, die, where_offset, scope_die))
> +  if (!get_scope_die(rdr, die, where_offset, scope_die))
>       return "";
>   
> -  string scope_name = die_qualified_name(ctxt, &scope_die, where_offset);
> +  string scope_name = die_qualified_name(rdr, &scope_die, where_offset);
>     string separator = "::";
>   
>     string repr;
> @@ -10020,7 +9201,7 @@ die_qualified_decl_name(const read_context& ctxt,
>         repr = scope_name.empty() ? name : scope_name + separator + name;
>         break;
>       case DW_TAG_subprogram:
> -      repr = die_function_signature(ctxt, die, where_offset);
> +      repr = die_function_signature(rdr, die, where_offset);
>         break;
>   
>       case DW_TAG_unspecified_parameters:
> @@ -10046,7 +9227,7 @@ die_qualified_decl_name(const read_context& ctxt,
>   /// DW_TAG_subprogram is going to be considered as a "type" -- just
>   /// like if it was a DW_TAG_subroutine_type.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the DWARF reader.
>   ///
>   /// @param die the DIE to consider.
>   ///
> @@ -10054,12 +9235,12 @@ die_qualified_decl_name(const read_context& ctxt,
>   ///
>   /// @return a copy of the computed name.
>   static string
> -die_qualified_name(const read_context& ctxt, const Dwarf_Die* die, size_t where)
> +die_qualified_name(const reader& rdr, const Dwarf_Die* die, size_t where)
>   {
>     if (die_is_type(die))
> -    return die_qualified_type_name(ctxt, die, where);
> +    return die_qualified_type_name(rdr, die, where);
>     else if (die_is_decl(die))
> -    return die_qualified_decl_name(ctxt, die, where);
> +    return die_qualified_decl_name(rdr, die, where);
>     return "";
>   }
>   
> @@ -10070,7 +9251,7 @@ die_qualified_name(const read_context& ctxt, const Dwarf_Die* die, size_t where)
>   /// that tag; or if the DIE's qualified name is built from names of
>   /// sub-types DIEs whose tags are not yet supported.
>   ///
> -/// @param ctxt the reading context.
> +/// @param rdr the DWARF reader.
>   ///
>   /// @param die the DIE to consider.
>   ///
> @@ -10081,7 +9262,7 @@ die_qualified_name(const read_context& ctxt, const Dwarf_Die* die, size_t where)
>   ///
>   /// @return true if the qualified name of the DIE is empty.
>   static bool
> -die_qualified_type_name_empty(const read_context& ctxt,
> +die_qualified_type_name_empty(const reader& rdr,
>   			      const Dwarf_Die* die,
>   			      size_t where, string &qualified_name)
>   {
> @@ -10104,19 +9285,19 @@ die_qualified_type_name_empty(const read_context& ctxt,
>         if (die_die_attribute(die, DW_AT_type, underlying_type_die))
>   	{
>   	  string name =
> -	    die_qualified_type_name(ctxt, &underlying_type_die, where);
> +	    die_qualified_type_name(rdr, &underlying_type_die, where);
>   	  if (name.empty())
>   	    return true;
>   	}
>       }
>     else
>       {
> -      string name = die_qualified_type_name(ctxt, die, where);
> +      string name = die_qualified_type_name(rdr, die, where);
>         if (name.empty())
>   	return true;
>       }
>   
> -  qname = die_qualified_type_name(ctxt, die, where);
> +  qname = die_qualified_type_name(rdr, die, where);
>     if (qname.empty())
>       return true;
>   
> @@ -10134,7 +9315,7 @@ die_qualified_type_name_empty(const read_context& ctxt,
>   /// When the function we are looking at is a member function, it also
>   /// tells if it's const.
>   ///
> -/// @param ctxt the reading context.
> +/// @param rdr the DWARF reader.
>   ///
>   /// @param die the DIE of the function or function type we are looking
>   /// at.
> @@ -10160,7 +9341,7 @@ die_qualified_type_name_empty(const read_context& ctxt,
>   /// @param is_static out parameter.  If the function is a static
>   /// member function, then this is set to true.
>   static void
> -die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
> +die_return_and_parm_names_from_fn_type_die(const reader& rdr,
>   					   const Dwarf_Die* die,
>   					   size_t where_offset,
>   					   bool pretty_print,
> @@ -10177,22 +9358,22 @@ die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
>     else
>       return_type_name =
>         pretty_print
> -      ? ctxt.get_die_pretty_representation(&ret_type_die, where_offset)
> -      : ctxt.get_die_qualified_type_name(&ret_type_die, where_offset);
> +      ? rdr.get_die_pretty_representation(&ret_type_die, where_offset)
> +      : rdr.get_die_qualified_type_name(&ret_type_die, where_offset);
>   
>     if (return_type_name.empty())
>       return_type_name = "void";
>   
>     Dwarf_Die object_pointer_die, class_die;
>     bool is_method_type =
> -    die_function_type_is_method_type(ctxt, die, where_offset,
> +    die_function_type_is_method_type(rdr, die, where_offset,
>   				     object_pointer_die,
>   				     class_die, is_static);
>   
>     is_const = false;
>     if (is_method_type)
>       {
> -      class_name = ctxt.get_die_qualified_type_name(&class_die, where_offset);
> +      class_name = rdr.get_die_qualified_type_name(&class_die, where_offset);
>   
>         Dwarf_Die this_pointer_die;
>         Dwarf_Die pointed_to_die;
> @@ -10223,8 +9404,8 @@ die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
>   	      continue;
>   	    string qualified_name =
>   	      pretty_print
> -	      ? ctxt.get_die_pretty_representation(&parm_type_die, where_offset)
> -	      : ctxt.get_die_qualified_type_name(&parm_type_die, where_offset);
> +	      ? rdr.get_die_pretty_representation(&parm_type_die, where_offset)
> +	      : rdr.get_die_qualified_type_name(&parm_type_die, where_offset);
>   
>   	    if (qualified_name.empty())
>   	      continue;
> @@ -10248,11 +9429,11 @@ die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
>     if (class_name.empty())
>       {
>         Dwarf_Die parent_die;
> -      if (get_parent_die(ctxt, die, parent_die, where_offset))
> +      if (get_parent_die(rdr, die, parent_die, where_offset))
>   	{
>   	  if (die_is_class_type(&parent_die))
>   	    class_name =
> -	      ctxt.get_die_qualified_type_name(&parent_die, where_offset);
> +	      rdr.get_die_qualified_type_name(&parent_die, where_offset);
>   	}
>       }
>   }
> @@ -10260,7 +9441,7 @@ die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
>   /// This computes the signature of the a function declaration
>   /// represented by a DIE.
>   ///
> -/// @param ctxt the reading context.
> +/// @param rdr the DWARF reader.
>   ///
>   /// @param fn_die the DIE of the function to consider.
>   ///
> @@ -10269,14 +9450,14 @@ die_return_and_parm_names_from_fn_type_die(const read_context& ctxt,
>   ///
>   /// @return a copy of the computed function signature string.
>   static string
> -die_function_signature(const read_context& ctxt,
> +die_function_signature(const reader& rdr,
>   		       const Dwarf_Die *fn_die,
>   		       size_t where_offset)
>   {
>   
>     translation_unit::language lang;
>     bool has_lang = false;
> -  if ((has_lang = ctxt.get_die_language(fn_die, lang)))
> +  if ((has_lang = rdr.get_die_language(fn_die, lang)))
>       {
>         // In a binary originating from the C language, it's OK to use
>         // the linkage name of the function as a key for the map which
> @@ -10299,7 +9480,7 @@ die_function_signature(const read_context& ctxt,
>     string return_type_name;
>     Dwarf_Die ret_type_die;
>     if (die_die_attribute(fn_die, DW_AT_type, ret_type_die))
> -    return_type_name = ctxt.get_die_qualified_type_name(&ret_type_die,
> +    return_type_name = rdr.get_die_qualified_type_name(&ret_type_die,
>   							where_offset);
>   
>     if (return_type_name.empty())
> @@ -10307,8 +9488,8 @@ die_function_signature(const read_context& ctxt,
>   
>     Dwarf_Die scope_die;
>     string scope_name;
> -  if (get_scope_die(ctxt, fn_die, where_offset, scope_die))
> -    scope_name = ctxt.get_die_qualified_name(&scope_die, where_offset);
> +  if (get_scope_die(rdr, fn_die, where_offset, scope_die))
> +    scope_name = rdr.get_die_qualified_name(&scope_die, where_offset);
>     string fn_name = die_name(fn_die);
>     if (!scope_name.empty())
>       fn_name  = scope_name + "::" + fn_name;
> @@ -10318,7 +9499,7 @@ die_function_signature(const read_context& ctxt,
>     bool is_const = false;
>     bool is_static = false;
>   
> -  die_return_and_parm_names_from_fn_type_die(ctxt, fn_die, where_offset,
> +  die_return_and_parm_names_from_fn_type_die(rdr, fn_die, where_offset,
>   					     /*pretty_print=*/false,
>   					     return_type_name, class_name,
>   					     parm_names, is_const, is_static);
> @@ -10373,7 +9554,7 @@ die_function_signature(const read_context& ctxt,
>   /// Note that this function is also used to pretty print functions.
>   /// For functions, it prints the *type* of the function.
>   ///
> -/// @param ctxt the context to use.
> +/// @param rdr the context to use.
>   ///
>   /// @param the DIE of the type to pretty print.
>   ///
> @@ -10383,7 +9564,7 @@ die_function_signature(const read_context& ctxt,
>   ///
>   /// @return the resulting pretty representation.
>   static string
> -die_pretty_print_type(read_context& ctxt,
> +die_pretty_print_type(reader& rdr,
>   		      const Dwarf_Die* die,
>   		      size_t where_offset)
>   {
> @@ -10413,17 +9594,17 @@ die_pretty_print_type(read_context& ctxt,
>         break;
>   
>       case DW_TAG_namespace:
> -      repr = "namespace " + ctxt.get_die_qualified_type_name(die, where_offset);
> +      repr = "namespace " + rdr.get_die_qualified_type_name(die, where_offset);
>         break;
>   
>       case DW_TAG_base_type:
> -      repr = ctxt.get_die_qualified_type_name(die, where_offset);
> +      repr = rdr.get_die_qualified_type_name(die, where_offset);
>         break;
>   
>       case DW_TAG_typedef:
>         {
>   	string qualified_name;
> -	if (!die_qualified_type_name_empty(ctxt, die,
> +	if (!die_qualified_type_name_empty(rdr, die,
>   					   where_offset,
>   					   qualified_name))
>   	  repr = "typedef " + qualified_name;
> @@ -10436,13 +9617,13 @@ die_pretty_print_type(read_context& ctxt,
>       case DW_TAG_pointer_type:
>       case DW_TAG_reference_type:
>       case DW_TAG_rvalue_reference_type:
> -      repr = ctxt.get_die_qualified_type_name(die, where_offset);
> +      repr = rdr.get_die_qualified_type_name(die, where_offset);
>         break;
>   
>       case DW_TAG_enumeration_type:
>         {
>   	string qualified_name =
> -	  ctxt.get_die_qualified_type_name(die, where_offset);
> +	  rdr.get_die_qualified_type_name(die, where_offset);
>   	repr = "enum " + qualified_name;
>         }
>         break;
> @@ -10451,7 +9632,7 @@ die_pretty_print_type(read_context& ctxt,
>       case DW_TAG_class_type:
>         {
>   	string qualified_name =
> -	  ctxt.get_die_qualified_type_name(die, where_offset);
> +	  rdr.get_die_qualified_type_name(die, where_offset);
>   	repr = "class " + qualified_name;
>         }
>         break;
> @@ -10459,7 +9640,7 @@ die_pretty_print_type(read_context& ctxt,
>       case DW_TAG_union_type:
>         {
>   	string qualified_name =
> -	  ctxt.get_die_qualified_type_name(die, where_offset);
> +	  rdr.get_die_qualified_type_name(die, where_offset);
>   	repr = "union " + qualified_name;
>         }
>         break;
> @@ -10470,12 +9651,12 @@ die_pretty_print_type(read_context& ctxt,
>   	if (!die_die_attribute(die, DW_AT_type, element_type_die))
>   	  break;
>   	string element_type_name =
> -	  ctxt.get_die_qualified_type_name(&element_type_die, where_offset);
> +	  rdr.get_die_qualified_type_name(&element_type_die, where_offset);
>   	if (element_type_name.empty())
>   	  break;
>   
>   	array_type_def::subranges_type subranges;
> -	build_subranges_from_array_type_die(ctxt, die, subranges, where_offset,
> +	build_subranges_from_array_type_die(rdr, die, subranges, where_offset,
>   					    /*associate_type_to_die=*/false);
>   
>   	repr = element_type_name;
> @@ -10493,7 +9674,7 @@ die_pretty_print_type(read_context& ctxt,
>   	// subrange type is its name.  We might need something more
>   	// advance, should the needs of the users get more
>   	// complicated.
> -	repr += die_qualified_type_name(ctxt, die, where_offset);
> +	repr += die_qualified_type_name(rdr, die, where_offset);
>         }
>         break;
>   
> @@ -10506,7 +9687,7 @@ die_pretty_print_type(read_context& ctxt,
>   	bool is_const = false;
>   	bool is_static = false;
>   
> -	die_return_and_parm_names_from_fn_type_die(ctxt, die, where_offset,
> +	die_return_and_parm_names_from_fn_type_die(rdr, die, where_offset,
>   						   /*pretty_print=*/true,
>   						   return_type_name, class_name,
>   						   parm_names, is_const,
> @@ -10515,7 +9696,7 @@ die_pretty_print_type(read_context& ctxt,
>   	  repr = "function type";
>   	else
>   	  repr = "method type";
> -	repr += " " + ctxt.get_die_qualified_type_name(die, where_offset);
> +	repr += " " + rdr.get_die_qualified_type_name(die, where_offset);
>         }
>         break;
>   
> @@ -10540,7 +9721,7 @@ die_pretty_print_type(read_context& ctxt,
>   /// Note that this function is also used to pretty print functions.
>   /// For functions, it prints the signature of the function.
>   ///
> -/// @param ctxt the context to use.
> +/// @param rdr the context to use.
>   ///
>   /// @param the DIE of the declaration to pretty print.
>   ///
> @@ -10550,7 +9731,7 @@ die_pretty_print_type(read_context& ctxt,
>   ///
>   /// @return the resulting pretty representation.
>   static string
> -die_pretty_print_decl(read_context& ctxt,
> +die_pretty_print_decl(reader& rdr,
>   		      const Dwarf_Die* die,
>   		      size_t where_offset)
>   {
> @@ -10563,7 +9744,7 @@ die_pretty_print_decl(read_context& ctxt,
>     switch (tag)
>       {
>       case DW_TAG_namespace:
> -      repr = "namespace " + die_qualified_name(ctxt, die, where_offset);
> +      repr = "namespace " + die_qualified_name(rdr, die, where_offset);
>         break;
>   
>       case DW_TAG_member:
> @@ -10572,15 +9753,15 @@ die_pretty_print_decl(read_context& ctxt,
>   	string type_repr = "void";
>   	Dwarf_Die type_die;
>   	if (die_die_attribute(die, DW_AT_type, type_die))
> -	  type_repr = die_qualified_type_name(ctxt, &type_die, where_offset);
> -	repr = die_qualified_name(ctxt, die, where_offset);
> +	  type_repr = die_qualified_type_name(rdr, &type_die, where_offset);
> +	repr = die_qualified_name(rdr, die, where_offset);
>   	if (!repr.empty())
>   	  repr = type_repr + " " + repr;
>         }
>         break;
>   
>       case DW_TAG_subprogram:
> -      repr = die_function_signature(ctxt, die, where_offset);
> +      repr = die_function_signature(rdr, die, where_offset);
>         break;
>   
>       default:
> @@ -10598,7 +9779,7 @@ die_pretty_print_decl(read_context& ctxt,
>   /// DW_TAG_subprogram DIE is going to be represented as a function
>   /// *type*.
>   ///
> -/// @param ctxt the reading context.
> +/// @param rdr the DWARF reader.
>   ///
>   /// @param die the DIE to consider.
>   ///
> @@ -10606,12 +9787,12 @@ die_pretty_print_decl(read_context& ctxt,
>   ///
>   /// @return a copy of the pretty printed artifact.
>   static string
> -die_pretty_print(read_context& ctxt, const Dwarf_Die* die, size_t where_offset)
> +die_pretty_print(reader& rdr, const Dwarf_Die* die, size_t where_offset)
>   {
>     if (die_is_type(die))
> -    return die_pretty_print_type(ctxt, die, where_offset);
> +    return die_pretty_print_type(rdr, die, where_offset);
>     else if (die_is_decl(die))
> -    return die_pretty_print_decl(ctxt, die, where_offset);
> +    return die_pretty_print_decl(rdr, die, where_offset);
>     return "";
>   }
>   
> @@ -10675,7 +9856,7 @@ compare_as_decl_dies(const Dwarf_Die *l, const Dwarf_Die *r)
>   
>   /// Test if at least one of two ODR-relevant DIEs is decl-only.
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param l the first type DIE to consider.
>   ///
> @@ -10684,11 +9865,11 @@ compare_as_decl_dies(const Dwarf_Die *l, const Dwarf_Die *r)
>   /// @return true iff either @p l or @p r is decl-only and both are
>   /// ODR-relevant.
>   static bool
> -at_least_one_decl_only_among_odr_relevant_dies(const read_context &ctxt,
> +at_least_one_decl_only_among_odr_relevant_dies(const reader &rdr,
>   					       const Dwarf_Die *l,
>   					       const Dwarf_Die *r)
>   {
> -  if (!(ctxt.odr_is_relevant(l) && ctxt.odr_is_relevant(r)))
> +  if (!(rdr.odr_is_relevant(l) && rdr.odr_is_relevant(r)))
>       return false;
>   
>     if ((die_is_declaration_only(l) && die_has_no_child(l))
> @@ -10711,7 +9892,7 @@ at_least_one_decl_only_among_odr_relevant_dies(const read_context &ctxt,
>   /// a declaration of a type compares equal to the definition of the
>   /// type.
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param l the left operand of the comparison operator.
>   ///
> @@ -10719,7 +9900,7 @@ at_least_one_decl_only_among_odr_relevant_dies(const read_context &ctxt,
>   ///
>   /// @return true iff @p l equals @p r.
>   static bool
> -compare_as_type_dies(const read_context& ctxt,
> +compare_as_type_dies(const reader& rdr,
>   		     const Dwarf_Die *l,
>   		     const Dwarf_Die *r)
>   {
> @@ -10738,7 +9919,7 @@ compare_as_type_dies(const read_context& ctxt,
>       // DW_TAG_string_type DIEs are different, by default.
>       return false;
>   
> -  if (at_least_one_decl_only_among_odr_relevant_dies(ctxt, l, r))
> +  if (at_least_one_decl_only_among_odr_relevant_dies(rdr, l, r))
>       // A declaration of a type compares equal to the definition of the
>       // type.
>       return true;
> @@ -10753,7 +9934,7 @@ compare_as_type_dies(const read_context& ctxt,
>   /// Compare two DIEs as decls (looking as their names etc) and as
>   /// types (looking at their size etc).
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param l the first DIE to consider.
>   ///
> @@ -10762,12 +9943,12 @@ compare_as_type_dies(const read_context& ctxt,
>   /// @return TRUE iff @p l equals @p r as far as naming and size is
>   /// concerned.
>   static bool
> -compare_as_decl_and_type_dies(const read_context &ctxt,
> +compare_as_decl_and_type_dies(const reader &rdr,
>   			      const Dwarf_Die *l,
>   			      const Dwarf_Die *r)
>   {
>     if (!compare_as_decl_dies(l, r)
> -      || !compare_as_type_dies(ctxt, l, r))
> +      || !compare_as_type_dies(rdr, l, r))
>       return false;
>   
>     return true;
> @@ -10782,7 +9963,7 @@ compare_as_decl_and_type_dies(const read_context &ctxt,
>   /// in C++ for instance, that doesn't imply that the two functions are
>   /// equal.
>   ///
> -/// @param ctxt the @ref read_context to consider.
> +/// @param rdr the @ref reader to consider.
>   ///
>   /// @param l the first function DIE to consider.
>   ///
> @@ -10791,7 +9972,7 @@ compare_as_decl_and_type_dies(const read_context &ctxt,
>   /// @return true iff the function represented by @p l have the same
>   /// linkage name as the function represented by @p r.
>   static bool
> -fn_die_equal_by_linkage_name(const read_context &ctxt,
> +fn_die_equal_by_linkage_name(const reader &rdr,
>   			     const Dwarf_Die *l,
>   			     const Dwarf_Die *r)
>   {
> @@ -10810,8 +9991,8 @@ fn_die_equal_by_linkage_name(const read_context &ctxt,
>     string llinkage_name = die_linkage_name(l),
>       rlinkage_name = die_linkage_name(r);
>   
> -  if (ctxt.die_is_in_c_or_cplusplus(l)
> -      && ctxt.die_is_in_c_or_cplusplus(r))
> +  if (rdr.die_is_in_c_or_cplusplus(l)
> +      && rdr.die_is_in_c_or_cplusplus(r))
>       {
>         if (!llinkage_name.empty() && !rlinkage_name.empty())
>   	return llinkage_name == rlinkage_name;
> @@ -10832,7 +10013,7 @@ fn_die_equal_by_linkage_name(const read_context &ctxt,
>   /// canonically and structurally.  The two types of comparison should
>   /// be equal, of course.
>   ///
> -/// @param ctxt the read_context.
> +/// @param rdr the DWARF reader.
>   ///
>   /// @param l_offset the offset of the first canonical DIE to compare.
>   ///
> @@ -10855,7 +10036,7 @@ fn_die_equal_by_linkage_name(const read_context &ctxt,
>   /// set to the offset of the canonical DIE of the DIE designated by @p
>   /// l_offset.
>   static bool
> -try_canonical_die_comparison(const read_context& ctxt,
> +try_canonical_die_comparison(const reader& rdr,
>   			     Dwarf_Off l_offset, Dwarf_Off r_offset,
>   			     die_source l_die_source, die_source r_die_source,
>   			     bool& l_has_canonical_die_offset,
> @@ -10865,20 +10046,20 @@ try_canonical_die_comparison(const read_context& ctxt,
>   			     bool& result)
>   {
>   #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
> -  if (ctxt.debug_die_canonicalization_is_on_
> -      && !ctxt.use_canonical_die_comparison_)
> +  if (rdr.debug_die_canonicalization_is_on_
> +      && !rdr.use_canonical_die_comparison_)
>       return false;
>   #endif
>   
>   
>     l_has_canonical_die_offset =
>       (l_canonical_die_offset =
> -     ctxt.get_canonical_die_offset(l_offset, l_die_source,
> +     rdr.get_canonical_die_offset(l_offset, l_die_source,
>   				   /*die_as_type=*/true));
>   
>     r_has_canonical_die_offset =
>       (r_canonical_die_offset =
> -     ctxt.get_canonical_die_offset(r_offset, r_die_source,
> +     rdr.get_canonical_die_offset(r_offset, r_die_source,
>   				   /*die_as_type=*/true));
>   
>     if (l_has_canonical_die_offset && r_has_canonical_die_offset)
> @@ -11085,7 +10266,7 @@ get_member_child_die(const Dwarf_Die *die, Dwarf_Die *child)
>   /// This optimization is performed only if
>   /// is_canon_type_to_be_propagated_tag returns true.
>   ///
> -/// @param ctxt the current context to consider.
> +/// @param rdr the current context to consider.
>   ///
>   /// @param l the left-hand-side DIE of the comparison.  It's going to
>   /// receive the canonical type of the other DIE.
> @@ -11093,7 +10274,7 @@ get_member_child_die(const Dwarf_Die *die, Dwarf_Die *child)
>   /// @param r the right-hand-side DIE of the comparison.  Its canonical
>   /// type is propagated to @p l.
>   static void
> -maybe_propagate_canonical_type(const read_context& ctxt,
> +maybe_propagate_canonical_type(const reader& rdr,
>   			       const Dwarf_Die* l,
>   			       const Dwarf_Die* r)
>   {
> @@ -11104,7 +10285,7 @@ maybe_propagate_canonical_type(const read_context& ctxt,
>       return;
>   
>     if (is_canon_type_to_be_propagated_tag(l_tag))
> -    propagate_canonical_type(ctxt, l, r);
> +    propagate_canonical_type(rdr, l, r);
>   }
>   
>   /// Propagate the canonical type of a the right-hand-side DIE to the
> @@ -11114,7 +10295,7 @@ maybe_propagate_canonical_type(const read_context& ctxt,
>   /// If the right-hand-side DIE is not canonicalized, the function
>   /// performs its canonicalization.
>   ///
> -/// @param ctxt the current context to consider.
> +/// @param rdr the current context to consider.
>   ///
>   /// @param l the left-hand-side DIE of the comparison.  It's going to
>   /// receive the canonical type of the other DIE.
> @@ -11122,7 +10303,7 @@ maybe_propagate_canonical_type(const read_context& ctxt,
>   /// @param r the right-hand-side DIE of the comparison.  Its canonical
>   /// type is propagated to @p l.
>   static void
> -propagate_canonical_type(const read_context& ctxt,
> +propagate_canonical_type(const reader& rdr,
>   			 const Dwarf_Die* l,
>   			 const Dwarf_Die* r)
>   {
> @@ -11133,8 +10314,8 @@ propagate_canonical_type(const read_context& ctxt,
>     //
>     // In case 'r' has no canonical DIE, then compute it, and then
>     // propagate that canonical DIE to 'r'.
> -  const die_source l_source = ctxt.get_die_source(l);
> -  const die_source r_source = ctxt.get_die_source(r);
> +  const die_source l_source = rdr.get_die_source(l);
> +  const die_source r_source = rdr.get_die_source(r);
>   
>     Dwarf_Off l_offset = dwarf_dieoffset(const_cast<Dwarf_Die*>(l));
>     Dwarf_Off r_offset = dwarf_dieoffset(const_cast<Dwarf_Die*>(r));
> @@ -11145,12 +10326,12 @@ propagate_canonical_type(const read_context& ctxt,
>   
>     l_has_canonical_die_offset =
>       (l_canonical_die_offset =
> -     ctxt.get_canonical_die_offset(l_offset, l_source,
> +     rdr.get_canonical_die_offset(l_offset, l_source,
>   				   /*die_as_type=*/true));
>   
>     r_has_canonical_die_offset =
>       (r_canonical_die_offset =
> -     ctxt.get_canonical_die_offset(r_offset, r_source,
> +     rdr.get_canonical_die_offset(r_offset, r_source,
>   				   /*die_as_type=*/true));
>   
>   
> @@ -11160,14 +10341,14 @@ propagate_canonical_type(const read_context& ctxt,
>         && l_source == r_source)
>       {
>         if (!r_has_canonical_die_offset)
> -	ctxt.compute_canonical_die_offset(r, r_canonical_die_offset,
> +	rdr.compute_canonical_die_offset(r, r_canonical_die_offset,
>   					  /*die_as_type=*/true);
>         ABG_ASSERT(r_canonical_die_offset);
> -      ctxt.set_canonical_die_offset(l, r_canonical_die_offset,
> +      rdr.set_canonical_die_offset(l, r_canonical_die_offset,
>   				    /*die_as_type=*/true);
>         offset_type l_off = {l_source, l_offset}, r_off = {r_source, r_offset};
> -      ctxt.propagated_types_.insert(std::make_pair(l_off,r_off));
> -      ctxt.canonical_propagated_count_++;
> +      rdr.propagated_types_.insert(std::make_pair(l_off,r_off));
> +      rdr.canonical_propagated_count_++;
>       }
>   }
>   
> @@ -11222,7 +10403,7 @@ return_comparison_result(const Dwarf_Die* l,
>         if (do_propagate_canonical_type)
>   	{
>   	  // Propagate canonical type.
> -	  maybe_propagate_canonical_type(comparison_stack.ctxt_, l, r);
> +	  maybe_propagate_canonical_type(comparison_stack.rdr_, l, r);
>   
>   	  // TODO: do we need to confirm any tentative canonical
>   	  // propagation?
> @@ -11287,7 +10468,7 @@ return_comparison_result(const Dwarf_Die* l,
>   	{
>   	  // We are in the case described above of a redundant type
>   	  // that has been fully compared.
> -	  maybe_propagate_canonical_type(comparison_stack.ctxt_, l, r);
> +	  maybe_propagate_canonical_type(comparison_stack.rdr_, l, r);
>   	  comparison_stack.confirm_canonical_propagated_type(cur_dies);
>   
>   	  result = COMPARISON_RESULT_EQUAL;
> @@ -11299,7 +10480,7 @@ return_comparison_result(const Dwarf_Die* l,
>   	  // the introductory comment above, it must be dependant on a
>   	  // redundant type.
>   	  ABG_ASSERT(comparison_stack.depends_on_redundant_types(cur_dies));
> -	  maybe_propagate_canonical_type(comparison_stack.ctxt_, l, r);
> +	  maybe_propagate_canonical_type(comparison_stack.rdr_, l, r);
>   	  // Then pass through.
>   	}
>       }
> @@ -11341,7 +10522,7 @@ return_comparison_result(const Dwarf_Die* l,
>       //and thus hasn't been pushed to the stack yet gain.
>       comparison_stack.erase(cur_dies);
>   
> -  maybe_cache_type_comparison_result(comparison_stack.ctxt_,
> +  maybe_cache_type_comparison_result(comparison_stack.rdr_,
>   				     l_tag, cur_dies, result);
>   
>     return result;
> @@ -11349,7 +10530,7 @@ return_comparison_result(const Dwarf_Die* l,
>   
>   /// Compare two DIEs emitted by a C compiler.
>   ///
> -/// @param ctxt the read context used to load the DWARF information.
> +/// @param rdr the DWARF reader used to load the DWARF information.
>   ///
>   /// @param l the left-hand-side argument of this comparison operator.
>   ///
> @@ -11371,7 +10552,7 @@ return_comparison_result(const Dwarf_Die* l,
>   ///
>   /// @return COMPARISON_RESULT_EQUAL iff @p l equals @p r.
>   static comparison_result
> -compare_dies(const read_context& ctxt,
> +compare_dies(const reader& rdr,
>   	     const Dwarf_Die *l, const Dwarf_Die *r,
>   	     offset_pairs_stack_type& aggregates_being_compared,
>   	     bool update_canonical_dies_on_the_fly)
> @@ -11379,8 +10560,8 @@ compare_dies(const read_context& ctxt,
>     ABG_ASSERT(l);
>     ABG_ASSERT(r);
>   
> -  const die_source l_die_source = ctxt.get_die_source(l);
> -  const die_source r_die_source = ctxt.get_die_source(r);
> +  const die_source l_die_source = rdr.get_die_source(l);
> +  const die_source r_die_source = rdr.get_die_source(r);
>   
>     offset_type l_offset =
>       {
> @@ -11406,7 +10587,7 @@ compare_dies(const read_context& ctxt,
>       return COMPARISON_RESULT_EQUAL;
>   
>     comparison_result result = COMPARISON_RESULT_EQUAL;
> -  if (maybe_get_cached_type_comparison_result(ctxt, l_tag,
> +  if (maybe_get_cached_type_comparison_result(rdr, l_tag,
>   					      dies_being_compared,
>   					      result))
>       return result;
> @@ -11419,7 +10600,7 @@ compare_dies(const read_context& ctxt,
>     if (is_type_die_to_be_canonicalized(l) && is_type_die_to_be_canonicalized(r))
>       {
>         bool canonical_compare_result = false;
> -      if (try_canonical_die_comparison(ctxt, l_offset, r_offset,
> +      if (try_canonical_die_comparison(rdr, l_offset, r_offset,
>   				       l_die_source, r_die_source,
>   				       l_has_canonical_die_offset,
>   				       r_has_canonical_die_offset,
> @@ -11444,7 +10625,7 @@ compare_dies(const read_context& ctxt,
>       case DW_TAG_base_type:
>       case DW_TAG_string_type:
>       case DW_TAG_unspecified_type:
> -      if (!compare_as_decl_and_type_dies(ctxt, l, r))
> +      if (!compare_as_decl_and_type_dies(rdr, l, r))
>   	SET_RESULT_TO_FALSE(result, l, r);
>         break;
>   
> @@ -11456,7 +10637,7 @@ compare_dies(const read_context& ctxt,
>       case DW_TAG_volatile_type:
>       case DW_TAG_restrict_type:
>         {
> -	if (!compare_as_type_dies(ctxt, l, r))
> +	if (!compare_as_type_dies(rdr, l, r))
>   	  {
>   	    SET_RESULT_TO_FALSE(result, l, r);
>   	    break;
> @@ -11493,14 +10674,14 @@ compare_dies(const read_context& ctxt,
>   	else if (lu_is_void != ru_is_void)
>   	  SET_RESULT_TO_FALSE(result, l, r);
>   	else
> -	  result = compare_dies(ctxt, &lu_type_die, &ru_type_die,
> +	  result = compare_dies(rdr, &lu_type_die, &ru_type_die,
>   				aggregates_being_compared,
>   				update_canonical_dies_on_the_fly);
>         }
>         break;
>   
>       case DW_TAG_enumeration_type:
> -      if (!compare_as_decl_and_type_dies(ctxt, l, r))
> +      if (!compare_as_decl_and_type_dies(rdr, l, r))
>   	SET_RESULT_TO_FALSE(result, l, r);
>         else
>   	{
> @@ -11508,7 +10689,7 @@ compare_dies(const read_context& ctxt,
>   	  Dwarf_Die l_enumtor, r_enumtor;
>   	  bool found_l_enumtor = true, found_r_enumtor = true;
>   
> -	  if (!at_least_one_decl_only_among_odr_relevant_dies(ctxt, l, r))
> +	  if (!at_least_one_decl_only_among_odr_relevant_dies(rdr, l, r))
>   	    for (found_l_enumtor = dwarf_child(const_cast<Dwarf_Die*>(l),
>   					       &l_enumtor) == 0,
>   		   found_r_enumtor = dwarf_child(const_cast<Dwarf_Die*>(r),
> @@ -11551,9 +10732,9 @@ compare_dies(const read_context& ctxt,
>         {
>   	RETURN_IF_COMPARISON_CYCLE_DETECTED;
>   
> -	ctxt.compare_count_++;
> +	rdr.compare_count_++;
>   
> -	if (!compare_as_decl_and_type_dies(ctxt, l, r))
> +	if (!compare_as_decl_and_type_dies(rdr, l, r))
>   	  SET_RESULT_TO_FALSE(result, l, r);
>   	else
>   	  {
> @@ -11562,7 +10743,7 @@ compare_dies(const read_context& ctxt,
>   	    Dwarf_Die l_member, r_member;
>   	    bool found_l_member = true, found_r_member = true;
>   
> -	    if (!at_least_one_decl_only_among_odr_relevant_dies(ctxt, l, r))
> +	    if (!at_least_one_decl_only_among_odr_relevant_dies(rdr, l, r))
>   	      for (found_l_member = get_member_child_die(l, &l_member),
>   		     found_r_member = get_member_child_die(r, &r_member);
>   		   found_l_member && found_r_member;
> @@ -11586,7 +10767,7 @@ compare_dies(const read_context& ctxt,
>   			     || l_tag == DW_TAG_subprogram);
>   
>   		  comparison_result local_result =
> -		    compare_dies(ctxt, &l_member, &r_member,
> +		    compare_dies(rdr, &l_member, &r_member,
>   				 aggregates_being_compared,
>   				 update_canonical_dies_on_the_fly);
>   
> @@ -11622,7 +10803,7 @@ compare_dies(const read_context& ctxt,
>   
>   	aggregates_being_compared.add(dies_being_compared);
>   
> -	ctxt.compare_count_++;
> +	rdr.compare_count_++;
>   
>   	Dwarf_Die l_child, r_child;
>   	bool found_l_child, found_r_child;
> @@ -11639,7 +10820,7 @@ compare_dies(const read_context& ctxt,
>   	    if (l_child_tag == DW_TAG_subrange_type
>   		|| r_child_tag == DW_TAG_subrange_type)
>   	      {
> -		result = compare_dies(ctxt, &l_child, &r_child,
> +		result = compare_dies(rdr, &l_child, &r_child,
>   				      aggregates_being_compared,
>   				      update_canonical_dies_on_the_fly);
>   		if (!result)
> @@ -11657,7 +10838,7 @@ compare_dies(const read_context& ctxt,
>   	bool found_rtype = die_die_attribute(r, DW_AT_type, rtype_die);
>   	ABG_ASSERT(found_ltype && found_rtype);
>   
> -	result = compare_dies(ctxt, &ltype_die, &rtype_die,
> +	result = compare_dies(rdr, &ltype_die, &rtype_die,
>   			      aggregates_being_compared,
>   			      update_canonical_dies_on_the_fly);
>   	  if (!result)
> @@ -11707,22 +10888,22 @@ compare_dies(const read_context& ctxt,
>   
>   	aggregates_being_compared.add(dies_being_compared);
>   
> -	ctxt.compare_count_++;
> +	rdr.compare_count_++;
>   
>   	if (l_tag == DW_TAG_subprogram
> -	    && !fn_die_equal_by_linkage_name(ctxt, l, r))
> +	    && !fn_die_equal_by_linkage_name(rdr, l, r))
>   	  {
>   	    SET_RESULT_TO_FALSE(result, l, r);
>   	    break;
>   	  }
>   	else if (l_tag == DW_TAG_subprogram
> -		 && ctxt.die_is_in_c(l) && ctxt.die_is_in_c(r)
> -		 /*&& fn_die_equal_by_linkage_name(ctxt, l, r)*/)
> +		 && rdr.die_is_in_c(l) && rdr.die_is_in_c(r)
> +		 /*&& fn_die_equal_by_linkage_name(rdr, l, r)*/)
>   	  {
>   	    result = COMPARISON_RESULT_EQUAL;
>   	    break;
>   	  }
> -	else if (!ctxt.die_is_in_c(l) && !ctxt.die_is_in_c(r))
> +	else if (!rdr.die_is_in_c(l) && !rdr.die_is_in_c(r))
>   	  {
>   	    // In C, we cannot have two different functions with the
>   	    // same linkage name in a given binary.  But here we are
> @@ -11735,7 +10916,7 @@ compare_dies(const read_context& ctxt,
>   							    r_return_type);
>   	    if (l_return_type_is_void != r_return_type_is_void
>   		|| (!l_return_type_is_void
> -		    && !compare_dies(ctxt,
> +		    && !compare_dies(rdr,
>   				     &l_return_type, &r_return_type,
>   				     aggregates_being_compared,
>   				     update_canonical_dies_on_the_fly)))
> @@ -11762,7 +10943,7 @@ compare_dies(const read_context& ctxt,
>   		      local_result = COMPARISON_RESULT_DIFFERENT;
>   		    if (l_child_tag == DW_TAG_formal_parameter)
>   		      local_result =
> -			compare_dies(ctxt, &l_child, &r_child,
> +			compare_dies(rdr, &l_child, &r_child,
>   				     aggregates_being_compared,
>   				     update_canonical_dies_on_the_fly);
>   		    if (local_result == COMPARISON_RESULT_DIFFERENT)
> @@ -11804,7 +10985,7 @@ compare_dies(const read_context& ctxt,
>   	else if (!l_type_is_void)
>   	  {
>   	    comparison_result local_result =
> -	      compare_dies(ctxt, &l_type, &r_type,
> +	      compare_dies(rdr, &l_type, &r_type,
>   			   aggregates_being_compared,
>   			   update_canonical_dies_on_the_fly);
>   	    SET_RESULT_TO(result, local_result, l, r);
> @@ -11820,8 +11001,8 @@ compare_dies(const read_context& ctxt,
>   	  if (l_tag == DW_TAG_member)
>   	    {
>   	      int64_t l_offset_in_bits = 0, r_offset_in_bits = 0;
> -	      die_member_offset(ctxt, l, l_offset_in_bits);
> -	      die_member_offset(ctxt, r, r_offset_in_bits);
> +	      die_member_offset(rdr, l, l_offset_in_bits);
> +	      die_member_offset(rdr, r, r_offset_in_bits);
>   	      if (l_offset_in_bits != r_offset_in_bits)
>   		SET_RESULT_TO_FALSE(result, l, r);
>   	    }
> @@ -11832,7 +11013,7 @@ compare_dies(const read_context& ctxt,
>   	      ABG_ASSERT(die_die_attribute(l, DW_AT_type, l_type));
>   	      ABG_ASSERT(die_die_attribute(r, DW_AT_type, r_type));
>   	      comparison_result local_result =
> -		compare_dies(ctxt, &l_type, &r_type,
> +		compare_dies(rdr, &l_type, &r_type,
>   			     aggregates_being_compared,
>   			     update_canonical_dies_on_the_fly);
>   	      SET_RESULT_TO(result, local_result, l, r);
> @@ -11847,7 +11028,7 @@ compare_dies(const read_context& ctxt,
>   	Dwarf_Die l_type, r_type;
>   	ABG_ASSERT(die_die_attribute(l, DW_AT_type, l_type));
>   	ABG_ASSERT(die_die_attribute(r, DW_AT_type, r_type));
> -	result = compare_dies(ctxt, &l_type, &r_type,
> +	result = compare_dies(rdr, &l_type, &r_type,
>   			       aggregates_being_compared,
>   			       update_canonical_dies_on_the_fly);
>   	if (!result)
> @@ -11865,8 +11046,8 @@ compare_dies(const read_context& ctxt,
>   	  ABG_RETURN(COMPARISON_RESULT_DIFFERENT);
>   
>   	int64_t l_offset_in_bits = 0, r_offset_in_bits = 0;
> -	die_member_offset(ctxt, l, l_offset_in_bits);
> -	die_member_offset(ctxt, r, r_offset_in_bits);
> +	die_member_offset(rdr, l, l_offset_in_bits);
> +	die_member_offset(rdr, r, r_offset_in_bits);
>   	if (l_offset_in_bits != r_offset_in_bits)
>   	  ABG_RETURN(COMPARISON_RESULT_DIFFERENT);
>         }
> @@ -11882,7 +11063,7 @@ compare_dies(const read_context& ctxt,
>   	Dwarf_Die l_type, r_type;
>   	ABG_ASSERT(die_die_attribute(l, DW_AT_type, l_type));
>   	ABG_ASSERT(die_die_attribute(r, DW_AT_type, r_type));
> -	result = compare_dies(ctxt, &l_type, &r_type,
> +	result = compare_dies(rdr, &l_type, &r_type,
>   			      aggregates_being_compared,
>   			      update_canonical_dies_on_the_fly);
>   	if (!result)
> @@ -11890,7 +11071,7 @@ compare_dies(const read_context& ctxt,
>   
>   	ABG_ASSERT(die_die_attribute(l, DW_AT_containing_type, l_type));
>   	ABG_ASSERT(die_die_attribute(r, DW_AT_containing_type, r_type));
> -	result = compare_dies(ctxt, &l_type, &r_type,
> +	result = compare_dies(rdr, &l_type, &r_type,
>   			      aggregates_being_compared,
>   			      update_canonical_dies_on_the_fly);
>   	if (!result)
> @@ -11949,7 +11130,7 @@ compare_dies(const read_context& ctxt,
>       case DW_TAG_GNU_call_site_parameter:
>       case DW_TAG_hi_user:
>   #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
> -      if (ctxt.debug_die_canonicalization_is_on_)
> +      if (rdr.debug_die_canonicalization_is_on_)
>   	ABG_ASSERT_NOT_REACHED;
>   #endif
>         ABG_ASSERT_NOT_REACHED;
> @@ -11961,7 +11142,7 @@ compare_dies(const read_context& ctxt,
>   
>   /// Compare two DIEs emitted by a C compiler.
>   ///
> -/// @param ctxt the read context used to load the DWARF information.
> +/// @param rdr the DWARF reader used to load the DWARF information.
>   ///
>   /// @param l the left-hand-side argument of this comparison operator.
>   ///
> @@ -11976,25 +11157,25 @@ compare_dies(const read_context& ctxt,
>   ///
>   /// @return COMPARISON_RESULT_EQUAL iff @p l equals @p r.
>   static comparison_result
> -compare_dies(const read_context& ctxt,
> +compare_dies(const reader& rdr,
>   	     const Dwarf_Die *l,
>   	     const Dwarf_Die *r,
>   	     bool update_canonical_dies_on_the_fly)
>   {
> -  offset_pairs_stack_type aggregates_being_compared(ctxt);
> -  return compare_dies(ctxt, l, r, aggregates_being_compared,
> +  offset_pairs_stack_type aggregates_being_compared(rdr);
> +  return compare_dies(rdr, l, r, aggregates_being_compared,
>   		      update_canonical_dies_on_the_fly);
>   }
>   
>   /// Compare two DIEs for the purpose of canonicalization.
>   ///
> -/// This is a sub-routine of read_context::get_canonical_die.
> +/// This is a sub-routine of reader::get_canonical_die.
>   ///
>   /// When DIE canonicalization debugging is on, this function performs
>   /// both structural and canonical comparison.  It expects that both
>   /// comparison yield the same result.
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the DWARF reader.
>   ///
>   /// @param l the left-hand-side comparison operand DIE.
>   ///
> @@ -12005,20 +11186,20 @@ compare_dies(const read_context& ctxt,
>   ///
>   /// @return true iff @p l equals @p r.
>   static bool
> -compare_dies_during_canonicalization(read_context& ctxt,
> +compare_dies_during_canonicalization(reader& rdr,
>   				     const Dwarf_Die *l,
>   				     const Dwarf_Die *r,
>   				     bool update_canonical_dies_on_the_fly)
>   {
>   #ifdef WITH_DEBUG_TYPE_CANONICALIZATION
> -  if (ctxt.debug_die_canonicalization_is_on_)
> +  if (rdr.debug_die_canonicalization_is_on_)
>       {
>         bool canonical_equality = false, structural_equality = false;
> -      ctxt.use_canonical_die_comparison_ = false;
> -      structural_equality = compare_dies(ctxt, l, r,
> +      rdr.use_canonical_die_comparison_ = false;
> +      structural_equality = compare_dies(rdr, l, r,
>   					 /*update_canonical_dies_on_the_fly=*/false);
> -      ctxt.use_canonical_die_comparison_ = true;
> -      canonical_equality = compare_dies(ctxt, l, r,
> +      rdr.use_canonical_die_comparison_ = true;
> +      canonical_equality = compare_dies(rdr, l, r,
>   					update_canonical_dies_on_the_fly);
>         if (canonical_equality != structural_equality)
>   	{
> @@ -12028,7 +11209,7 @@ compare_dies_during_canonicalization(read_context& ctxt,
>   		    << ", r: " << dwarf_dieoffset(const_cast<Dwarf_Die*>(r))
>   		    << std::dec
>   		    << ", repr: '"
> -		    << ctxt.get_die_pretty_type_representation(l, 0)
> +		    << rdr.get_die_pretty_type_representation(l, 0)
>   		    << "'"
>   		    << std::endl;
>   	  ABG_ASSERT_NOT_REACHED;
> @@ -12036,7 +11217,7 @@ compare_dies_during_canonicalization(read_context& ctxt,
>         return structural_equality;
>       }
>   #endif
> -  return compare_dies(ctxt, l, r,
> +  return compare_dies(rdr, l, r,
>   		      update_canonical_dies_on_the_fly);
>   }
>   
> @@ -12047,7 +11228,7 @@ compare_dies_during_canonicalization(read_context& ctxt,
>   /// Get the point where a DW_AT_import DIE is used to import a given
>   /// (unit) DIE, between two DIEs.
>   ///
> -/// @param ctxt the dwarf reading context to consider.
> +/// @param rdr the dwarf reader to consider.
>   ///
>   /// @param partial_unit_offset the imported unit for which we want to
>   /// know the insertion point.  This is usually a partial unit (with
> @@ -12079,7 +11260,7 @@ compare_dies_during_canonicalization(read_context& ctxt,
>   /// @return true iff an imported unit is found between @p
>   /// first_die_offset and @p last_die_offset.
>   static bool
> -find_import_unit_point_between_dies(const read_context& ctxt,
> +find_import_unit_point_between_dies(const reader& rdr,
>   				    size_t		partial_unit_offset,
>   				    Dwarf_Off		first_die_offset,
>   				    Dwarf_Off		first_die_cu_offset,
> @@ -12088,7 +11269,7 @@ find_import_unit_point_between_dies(const read_context& ctxt,
>   				    size_t&		imported_point_offset)
>   {
>     const tu_die_imported_unit_points_map_type& tu_die_imported_unit_points_map =
> -    ctxt.tu_die_imported_unit_points_map(source);
> +    rdr.tu_die_imported_unit_points_map(source);
>   
>     tu_die_imported_unit_points_map_type::const_iterator iter =
>       tu_die_imported_unit_points_map.find(first_die_cu_offset);
> @@ -12122,7 +11303,7 @@ find_import_unit_point_between_dies(const read_context& ctxt,
>   
>         for (imported_unit_points_type::const_iterator i = e; i >= b; --i)
>   	{
> -	  if (find_import_unit_point_between_dies(ctxt,
> +	  if (find_import_unit_point_between_dies(rdr,
>   						  partial_unit_offset,
>   						  i->imported_unit_child_off,
>   						  i->imported_unit_cu_off,
> @@ -12143,7 +11324,7 @@ find_import_unit_point_between_dies(const read_context& ctxt,
>   
>         for (imported_unit_points_type::const_iterator i = b; i != e; ++i)
>   	{
> -	  if (find_import_unit_point_between_dies(ctxt,
> +	  if (find_import_unit_point_between_dies(rdr,
>   						  partial_unit_offset,
>   						  i->imported_unit_child_off,
>   						  i->imported_unit_cu_off,
> @@ -12164,7 +11345,7 @@ find_import_unit_point_between_dies(const read_context& ctxt,
>   /// Said otherwise, this function returns the last import point of a
>   /// unit, before a limit.
>   ///
> -/// @param ctxt the dwarf reading context to consider.
> +/// @param rdr the dwarf reader to consider.
>   ///
>   /// @param partial_unit_offset the imported unit for which we want to
>   /// know the insertion point of.  This is usually a partial unit (with
> @@ -12182,7 +11363,7 @@ find_import_unit_point_between_dies(const read_context& ctxt,
>   /// Note that if an imported unit is found after @p die_offset then @p
>   /// imported_point_offset is set and the function return false.
>   static bool
> -find_import_unit_point_before_die(const read_context&	ctxt,
> +find_import_unit_point_before_die(const reader&	rdr,
>   				  size_t		partial_unit_offset,
>   				  size_t		where_offset,
>   				  size_t&		imported_point_offset)
> @@ -12190,7 +11371,7 @@ find_import_unit_point_before_die(const read_context&	ctxt,
>     size_t import_point_offset = 0;
>     Dwarf_Die first_die_of_tu;
>   
> -  if (dwarf_child(const_cast<Dwarf_Die*>(ctxt.cur_tu_die()),
> +  if (dwarf_child(const_cast<Dwarf_Die*>(rdr.cur_tu_die()),
>   		  &first_die_of_tu) != 0)
>       return false;
>   
> @@ -12200,7 +11381,7 @@ find_import_unit_point_before_die(const read_context&	ctxt,
>     cu_die = dwarf_diecu(const_cast<Dwarf_Die*>(&first_die_of_tu),
>   		       &cu_die_memory, 0, 0);
>   
> -  if (find_import_unit_point_between_dies(ctxt, partial_unit_offset,
> +  if (find_import_unit_point_between_dies(rdr, partial_unit_offset,
>   					  dwarf_dieoffset(&first_die_of_tu),
>   					  dwarf_dieoffset(cu_die),
>   					  /*source=*/PRIMARY_DEBUG_INFO_DIE_SOURCE,
> @@ -12226,7 +11407,7 @@ find_import_unit_point_before_die(const read_context&	ctxt,
>   /// called before this one can work.  This function either succeeds or
>   /// aborts the current process.
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param die the DIE for which we want the parent.
>   ///
> @@ -12241,16 +11422,16 @@ find_import_unit_point_before_die(const read_context&	ctxt,
>   /// @return true if the function could get a parent DIE, false
>   /// otherwise.
>   static bool
> -get_parent_die(const read_context&	ctxt,
> +get_parent_die(const reader&	rdr,
>   	       const Dwarf_Die*	die,
>   	       Dwarf_Die&		parent_die,
>   	       size_t			where_offset)
>   {
> -  ABG_ASSERT(ctxt.dwarf());
> +  ABG_ASSERT(rdr.dwarf_debug_info());
>   
> -  const die_source source = ctxt.get_die_source(die);
> +  const die_source source = rdr.get_die_source(die);
>   
> -  const offset_offset_map_type& m = ctxt.die_parent_map(source);
> +  const offset_offset_map_type& m = rdr.die_parent_map(source);
>     offset_offset_map_type::const_iterator i =
>       m.find(dwarf_dieoffset(const_cast<Dwarf_Die*>(die)));
>   
> @@ -12260,13 +11441,16 @@ get_parent_die(const read_context&	ctxt,
>     switch (source)
>       {
>       case PRIMARY_DEBUG_INFO_DIE_SOURCE:
> -      ABG_ASSERT(dwarf_offdie(ctxt.dwarf(), i->second, &parent_die));
> +      ABG_ASSERT(dwarf_offdie(const_cast<Dwarf*>(rdr.dwarf_debug_info()),
> +			      i->second, &parent_die));
>         break;
>       case ALT_DEBUG_INFO_DIE_SOURCE:
> -      ABG_ASSERT(dwarf_offdie(ctxt.alt_dwarf(), i->second, &parent_die));
> +      ABG_ASSERT(dwarf_offdie(const_cast<Dwarf*>(rdr.alternate_dwarf_debug_info()),
> +			      i->second, &parent_die));
>         break;
>       case TYPE_UNIT_DIE_SOURCE:
> -      ABG_ASSERT(dwarf_offdie_types(ctxt.dwarf(), i->second, &parent_die));
> +      ABG_ASSERT(dwarf_offdie_types(const_cast<Dwarf*>(rdr.dwarf_debug_info()),
> +				    i->second, &parent_die));
>         break;
>       case NO_DEBUG_INFO_DIE_SOURCE:
>       case NUMBER_OF_DIE_SOURCES:
> @@ -12277,12 +11461,12 @@ get_parent_die(const read_context&	ctxt,
>       {
>         if (where_offset == 0)
>   	{
> -	  parent_die = *ctxt.cur_tu_die();
> +	  parent_die = *rdr.cur_tu_die();
>   	  return true;
>   	}
>         size_t import_point_offset = 0;
>         bool found =
> -	find_import_unit_point_before_die(ctxt,
> +	find_import_unit_point_before_die(rdr,
>   					  dwarf_dieoffset(&parent_die),
>   					  where_offset,
>   					  import_point_offset);
> @@ -12291,15 +11475,15 @@ get_parent_die(const read_context&	ctxt,
>   	// debug info file) hasn't been imported into this TU.  So,
>   	// Let's assume its logical parent is the DIE of the current
>   	// TU.
> -	parent_die = *ctxt.cur_tu_die();
> +	parent_die = *rdr.cur_tu_die();
>         else
>   	{
>   	  ABG_ASSERT(import_point_offset);
>   	  Dwarf_Die import_point_die;
> -	  ABG_ASSERT(dwarf_offdie(ctxt.dwarf(),
> -			      import_point_offset,
> -			      &import_point_die));
> -	  return get_parent_die(ctxt, &import_point_die,
> +	  ABG_ASSERT(dwarf_offdie(const_cast<Dwarf*>(rdr.dwarf_debug_info()),
> +				  import_point_offset,
> +				  &import_point_die));
> +	  return get_parent_die(rdr, &import_point_die,
>   				parent_die, where_offset);
>   	}
>       }
> @@ -12318,7 +11502,7 @@ get_parent_die(const read_context&	ctxt,
>   /// Also note that if the current translation unit is from C, then
>   /// this returns the global scope.
>   ///
> -/// @param ctxt the reading context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @param die the DIE to consider.
>   ///
> @@ -12327,12 +11511,12 @@ get_parent_die(const read_context&	ctxt,
>   /// @param scope_die out parameter.  This is set to the resulting
>   /// scope DIE iff the function returns true.
>   static bool
> -get_scope_die(const read_context&	ctxt,
> +get_scope_die(const reader&	rdr,
>   	      const Dwarf_Die*		die,
>   	      size_t			where_offset,
>   	      Dwarf_Die&		scope_die)
>   {
> -  if (is_c_language(ctxt.cur_transl_unit()->get_language()))
> +  if (is_c_language(rdr.cur_transl_unit()->get_language()))
>       {
>         ABG_ASSERT(dwarf_tag(const_cast<Dwarf_Die*>(die)) != DW_TAG_member);
>         return dwarf_diecu(const_cast<Dwarf_Die*>(die), &scope_die, 0, 0);
> @@ -12343,15 +11527,15 @@ get_scope_die(const read_context&	ctxt,
>   			logical_parent_die, false)
>         || die_die_attribute(die, DW_AT_abstract_origin,
>   			   logical_parent_die, false))
> -    return get_scope_die(ctxt, &logical_parent_die, where_offset, scope_die);
> +    return get_scope_die(rdr, &logical_parent_die, where_offset, scope_die);
>   
> -  if (!get_parent_die(ctxt, die, scope_die, where_offset))
> +  if (!get_parent_die(rdr, die, scope_die, where_offset))
>       return false;
>   
>     if (dwarf_tag(&scope_die) == DW_TAG_subprogram
>         || dwarf_tag(&scope_die) == DW_TAG_subroutine_type
>         || dwarf_tag(&scope_die) == DW_TAG_array_type)
> -    return get_scope_die(ctxt, &scope_die, where_offset, scope_die);
> +    return get_scope_die(rdr, &scope_die, where_offset, scope_die);
>   
>     return true;
>   }
> @@ -12366,7 +11550,7 @@ get_scope_die(const read_context&	ctxt,
>   /// Also note that if the current translation unit is from C, then
>   /// this returns the global scope.
>   ///
> -/// @param ctxt the dwarf reading context to use.
> +/// @param rdr the dwarf reader to use.
>   ///
>   /// @param die the DIE to get the scope for.
>   ///
> @@ -12378,36 +11562,36 @@ get_scope_die(const read_context&	ctxt,
>   /// e.g, DW_TAG_partial_unit that can be included in several places in
>   /// the DIE tree.
>   static scope_decl_sptr
> -get_scope_for_die(read_context& ctxt,
> +get_scope_for_die(reader& rdr,
>   		  Dwarf_Die*	die,
>   		  bool		called_for_public_decl,
>   		  size_t	where_offset)
>   {
> -  const die_source source_of_die = ctxt.get_die_source(die);
> +  const die_source source_of_die = rdr.get_die_source(die);
>   
>     translation_unit::language die_lang = translation_unit::LANG_UNKNOWN;
> -  ctxt.get_die_language(die, die_lang);
> +  rdr.get_die_language(die, die_lang);
>     if (is_c_language(die_lang)
> -      || ctxt.die_parent_map(source_of_die).empty())
> +      || rdr.die_parent_map(source_of_die).empty())
>       {
>         // In units for the C languages all decls belong to the global
>         // namespace.  This is generally the case if Libabigail
>         // determined that no DIE -> parent map was needed.
>         ABG_ASSERT(dwarf_tag(die) != DW_TAG_member);
> -      return ctxt.global_scope();
> +      return rdr.global_scope();
>       }
>   
>     Dwarf_Die cloned_die;
>     if (die_die_attribute(die, DW_AT_specification, cloned_die, false)
>         || die_die_attribute(die, DW_AT_abstract_origin, cloned_die, false))
> -    return get_scope_for_die(ctxt, &cloned_die,
> +    return get_scope_for_die(rdr, &cloned_die,
>   			     called_for_public_decl,
>   			     where_offset);
>   
>     Dwarf_Die parent_die;
>   
> -  if (!get_parent_die(ctxt, die, parent_die, where_offset))
> -    return ctxt.nil_scope();
> +  if (!get_parent_die(rdr, die, parent_die, where_offset))
> +    return rdr.nil_scope();
>   
>     if (dwarf_tag(&parent_die) == DW_TAG_compile_unit
>         || dwarf_tag(&parent_die) == DW_TAG_partial_unit
> @@ -12418,7 +11602,7 @@ get_scope_for_die(read_context& ctxt,
>   	{
>   	  ABG_ASSERT(source_of_die == ALT_DEBUG_INFO_DIE_SOURCE
>   		 || source_of_die == TYPE_UNIT_DIE_SOURCE);
> -	  return ctxt.cur_transl_unit()->get_global_scope();
> +	  return rdr.cur_transl_unit()->get_global_scope();
>   	}
>   
>         // For top level DIEs like DW_TAG_compile_unit, we just want to
> @@ -12428,10 +11612,10 @@ get_scope_for_die(read_context& ctxt,
>         // build the translation unit of parent_die.  Otherwise, just
>         // return the global scope of the current translation unit.
>         die_tu_map_type::const_iterator i =
> -	ctxt.die_tu_map().find(dwarf_dieoffset(&parent_die));
> -      if (i != ctxt.die_tu_map().end())
> +	rdr.die_tu_map().find(dwarf_dieoffset(&parent_die));
> +      if (i != rdr.die_tu_map().end())
>   	return i->second->get_global_scope();
> -      return ctxt.cur_transl_unit()->get_global_scope();
> +      return rdr.cur_transl_unit()->get_global_scope();
>       }
>   
>     scope_decl_sptr s;
> @@ -12448,7 +11632,7 @@ get_scope_for_die(read_context& ctxt,
>       // an error of the DWARF emitter.  We should never see this DIE in
>       // this context.
>       {
> -      scope_decl_sptr s = get_scope_for_die(ctxt, &parent_die,
> +      scope_decl_sptr s = get_scope_for_die(rdr, &parent_die,
>   					    called_for_public_decl,
>   					    where_offset);
>         if (is_anonymous_type_die(die))
> @@ -12458,23 +11642,23 @@ get_scope_for_die(read_context& ctxt,
>   	// or union where it has nothing to do.
>   	while (is_class_or_union_type(s))
>   	  {
> -	    if (!get_parent_die(ctxt, &parent_die, parent_die, where_offset))
> -	      return ctxt.nil_scope();
> -	    s = get_scope_for_die(ctxt, &parent_die,
> +	    if (!get_parent_die(rdr, &parent_die, parent_die, where_offset))
> +	      return rdr.nil_scope();
> +	    s = get_scope_for_die(rdr, &parent_die,
>   				  called_for_public_decl,
>   				  where_offset);
>   	  }
>         return s;
>       }
>     else
> -    d = build_ir_node_from_die(ctxt, &parent_die,
> +    d = build_ir_node_from_die(rdr, &parent_die,
>   			       called_for_public_decl,
>   			       where_offset);
>     s =  dynamic_pointer_cast<scope_decl>(d);
>     if (!s)
>       // this is an entity defined in someting that is not a scope.
>       // Let's drop it.
> -    return ctxt.nil_scope();
> +    return rdr.nil_scope();
>   
>     class_decl_sptr cl = dynamic_pointer_cast<class_decl>(d);
>     if (cl && cl->get_is_declaration_only())
> @@ -12689,7 +11873,7 @@ find_lower_bound_in_imported_unit_points(const imported_unit_points_type& p,
>   /// recursively reads the children dies of the current DIE and
>   /// populates the resulting translation unit.
>   ///
> -/// @param ctxt the read_context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @param die the DW_TAG_compile_unit DIE to consider.
>   ///
> @@ -12698,7 +11882,7 @@ find_lower_bound_in_imported_unit_points(const imported_unit_points_type& p,
>   ///
>   /// @return a pointer to the resulting translation_unit.
>   static translation_unit_sptr
> -build_translation_unit_and_add_to_ir(read_context&	ctxt,
> +build_translation_unit_and_add_to_ir(reader&	rdr,
>   				     Dwarf_Die*	die,
>   				     char		address_size)
>   {
> @@ -12710,9 +11894,9 @@ build_translation_unit_and_add_to_ir(read_context&	ctxt,
>   
>     // Clear the part of the context that is dependent on the translation
>     // unit we are reading.
> -  ctxt.clear_per_translation_unit_data();
> +  rdr.clear_per_translation_unit_data();
>   
> -  ctxt.cur_tu_die(die);
> +  rdr.cur_tu_die(die);
>   
>     string path = die_string_attribute(die, DW_AT_name);
>     if (path == "<artificial>")
> @@ -12737,23 +11921,23 @@ build_translation_unit_and_add_to_ir(read_context&	ctxt,
>     {
>       const string& abs_path =
>         compilation_dir.empty() ? path : compilation_dir + "/" + path;
> -    result = ctxt.current_corpus()->find_translation_unit(abs_path);
> +    result = rdr.corpus()->find_translation_unit(abs_path);
>     }
>   
>     if (!result)
>       {
> -      result.reset(new translation_unit(ctxt.env(),
> +      result.reset(new translation_unit(rdr.env(),
>   					path,
>   					address_size));
>         result->set_compilation_dir_path(compilation_dir);
> -      ctxt.current_corpus()->add(result);
> +      rdr.corpus()->add(result);
>         uint64_t l = 0;
>         die_unsigned_constant_attribute(die, DW_AT_language, l);
>         result->set_language(dwarf_language_to_tu_language(l));
>       }
>   
> -  ctxt.cur_transl_unit(result);
> -  ctxt.die_tu_map()[dwarf_dieoffset(die)] = result;
> +  rdr.cur_transl_unit(result);
> +  rdr.die_tu_map()[dwarf_dieoffset(die)] = result;
>   
>     Dwarf_Die child;
>     if (dwarf_child(die, &child) != 0)
> @@ -12764,17 +11948,17 @@ build_translation_unit_and_add_to_ir(read_context&	ctxt,
>     do
>       // Analyze all the DIEs we encounter unless we are asked to only
>       // analyze exported interfaces and the types reachables from them.
> -    if (!ctxt.env()->analyze_exported_interfaces_only()
> -	|| ctxt.is_decl_die_with_exported_symbol(&child))
> -      build_ir_node_from_die(ctxt, &child,
> +    if (!rdr.env().analyze_exported_interfaces_only()
> +	|| rdr.is_decl_die_with_exported_symbol(&child))
> +      build_ir_node_from_die(rdr, &child,
>   			     die_is_public_decl(&child),
>   			     dwarf_dieoffset(&child));
>     while (dwarf_siblingof(&child, &child) == 0);
>   
> -  if (!ctxt.var_decls_to_re_add_to_tree().empty())
> +  if (!rdr.var_decls_to_re_add_to_tree().empty())
>       for (list<var_decl_sptr>::const_iterator v =
> -	   ctxt.var_decls_to_re_add_to_tree().begin();
> -	 v != ctxt.var_decls_to_re_add_to_tree().end();
> +	   rdr.var_decls_to_re_add_to_tree().begin();
> +	 v != rdr.var_decls_to_re_add_to_tree().end();
>   	 ++v)
>         {
>   	if (is_member_decl(*v))
> @@ -12795,7 +11979,7 @@ build_translation_unit_and_add_to_ir(read_context&	ctxt,
>   	      {
>   		ty_name = components_to_type_name(fqn_comps);
>   		class_type =
> -		  lookup_class_type(ty_name, *ctxt.cur_transl_unit());
> +		  lookup_class_type(ty_name, *rdr.cur_transl_unit());
>   	      }
>   	    if (class_type)
>   	      {
> @@ -12825,7 +12009,7 @@ build_translation_unit_and_add_to_ir(read_context&	ctxt,
>   	      }
>   	  }
>         }
> -  ctxt.var_decls_to_re_add_to_tree().clear();
> +  rdr.var_decls_to_re_add_to_tree().clear();
>   
>     result->set_is_constructed(true);
>   
> @@ -12839,7 +12023,7 @@ build_translation_unit_and_add_to_ir(read_context&	ctxt,
>   /// being currently created, reads the children of the DIE and
>   /// connects them to the IR as well.
>   ///
> -/// @param ctxt the read context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @param die the DIE to read from.  Must be either DW_TAG_namespace
>   /// or DW_TAG_module.
> @@ -12852,7 +12036,7 @@ build_translation_unit_and_add_to_ir(read_context&	ctxt,
>   /// @return the resulting @ref abigail::namespace_decl or NULL if it
>   /// couldn't be created.
>   static namespace_decl_sptr
> -build_namespace_decl_and_add_to_ir(read_context&	ctxt,
> +build_namespace_decl_and_add_to_ir(reader&	rdr,
>   				   Dwarf_Die*		die,
>   				   size_t		where_offset)
>   {
> @@ -12865,25 +12049,25 @@ build_namespace_decl_and_add_to_ir(read_context&	ctxt,
>     if (tag != DW_TAG_namespace && tag != DW_TAG_module)
>       return result;
>   
> -  scope_decl_sptr scope = get_scope_for_die(ctxt, die,
> +  scope_decl_sptr scope = get_scope_for_die(rdr, die,
>   					    /*called_for_public_decl=*/false,
>   					    where_offset);
>   
>     string name, linkage_name;
>     location loc;
> -  die_loc_and_name(ctxt, die, loc, name, linkage_name);
> +  die_loc_and_name(rdr, die, loc, name, linkage_name);
>   
> -  result.reset(new namespace_decl(ctxt.env(), name, loc));
> +  result.reset(new namespace_decl(rdr.env(), name, loc));
>     add_decl_to_scope(result, scope.get());
> -  ctxt.associate_die_to_decl(die, result, where_offset);
> +  rdr.associate_die_to_decl(die, result, where_offset);
>   
>     Dwarf_Die child;
>     if (dwarf_child(die, &child) != 0)
>       return result;
>   
> -  ctxt.scope_stack().push(result.get());
> +  rdr.scope_stack().push(result.get());
>     do
> -    build_ir_node_from_die(ctxt, &child,
> +    build_ir_node_from_die(rdr, &child,
>   			   // If this namespace DIE is private
>   			   // (anonymous) then all its content is
>   			   // considered private.  Otherwise, its
> @@ -12892,14 +12076,14 @@ build_namespace_decl_and_add_to_ir(read_context&	ctxt,
>   			   die_is_public_decl(die) && die_is_public_decl(&child),
>   			   where_offset);
>     while (dwarf_siblingof(&child, &child) == 0);
> -  ctxt.scope_stack().pop();
> +  rdr.scope_stack().pop();
>   
>     return result;
>   }
>   
>   /// Build a @ref type_decl out of a DW_TAG_base_type DIE.
>   ///
> -/// @param ctxt the read context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @param die the DW_TAG_base_type to consider.
>   ///
> @@ -12907,7 +12091,7 @@ build_namespace_decl_and_add_to_ir(read_context&	ctxt,
>   ///
>   /// @return the resulting decl_base_sptr.
>   static type_decl_sptr
> -build_type_decl(read_context& ctxt, Dwarf_Die* die, size_t where_offset)
> +build_type_decl(reader& rdr, Dwarf_Die* die, size_t where_offset)
>   {
>     type_decl_sptr result;
>   
> @@ -12926,21 +12110,21 @@ build_type_decl(read_context& ctxt, Dwarf_Die* die, size_t where_offset)
>   
>     string type_name, linkage_name;
>     location loc;
> -  die_loc_and_name(ctxt, die, loc, type_name, linkage_name);
> +  die_loc_and_name(rdr, die, loc, type_name, linkage_name);
>   
>     if (byte_size == 0)
>       {
>         // The size of the type is zero, that must mean that we are
>         // looking at the definition of the void type.
>         if (type_name == "void")
> -	result = is_type_decl(build_ir_node_for_void_type(ctxt));
> +	result = is_type_decl(build_ir_node_for_void_type(rdr));
>         else
>   	// A type of size zero that is not void? Hmmh, I am not sure
>   	// what that means.  Return nil for now.
>   	return result;
>       }
>   
> -  if (corpus_sptr corp = ctxt.should_reuse_type_from_corpus_group())
> +  if (corpus_sptr corp = rdr.should_reuse_type_from_corpus_group())
>       {
>         string normalized_type_name = type_name;
>         integral_type int_type;
> @@ -12950,19 +12134,19 @@ build_type_decl(read_context& ctxt, Dwarf_Die* die, size_t where_offset)
>       }
>   
>     if (!result)
> -    if (corpus_sptr corp = ctxt.current_corpus())
> +    if (corpus_sptr corp = rdr.corpus())
>         result = lookup_basic_type(type_name, *corp);
>     if (!result)
> -    result.reset(new type_decl(ctxt.env(), type_name, bit_size,
> +    result.reset(new type_decl(rdr.env(), type_name, bit_size,
>   			       /*alignment=*/0, loc, linkage_name));
> -  ctxt.associate_die_to_type(die, result, where_offset);
> +  rdr.associate_die_to_type(die, result, where_offset);
>     return result;
>   }
>   
>   /// Construct the type that is to be used as the underlying type of an
>   /// enum.
>   ///
> -/// @param ctxt the read context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @param enum_name the name of the enum that this type is going to
>   /// be the underlying type of.
> @@ -12973,7 +12157,7 @@ build_type_decl(read_context& ctxt, Dwarf_Die* die, size_t where_offset)
>   /// not. By default, this should be set to true as before c++11 (and
>   /// in C), it's almost the case.
>   static type_decl_sptr
> -build_enum_underlying_type(read_context& ctxt,
> +build_enum_underlying_type(reader& rdr,
>   			   string enum_name,
>   			   uint64_t enum_size,
>   			   bool is_anonymous = true)
> @@ -12982,11 +12166,11 @@ build_enum_underlying_type(read_context& ctxt,
>       build_internal_underlying_enum_type_name(enum_name, is_anonymous,
>   					     enum_size);
>   
> -  type_decl_sptr result(new type_decl(ctxt.env(), underlying_type_name,
> +  type_decl_sptr result(new type_decl(rdr.env(), underlying_type_name,
>   				      enum_size, enum_size, location()));
>     result->set_is_anonymous(is_anonymous);
>     result->set_is_artificial(true);
> -  translation_unit_sptr tu = ctxt.cur_transl_unit();
> +  translation_unit_sptr tu = rdr.cur_transl_unit();
>     decl_base_sptr d = add_decl_to_scope(result, tu->get_global_scope().get());
>     result = dynamic_pointer_cast<type_decl>(d);
>     ABG_ASSERT(result);
> @@ -12996,7 +12180,7 @@ build_enum_underlying_type(read_context& ctxt,
>   
>   /// Build an enum_type_decl from a DW_TAG_enumeration_type DIE.
>   ///
> -/// @param ctxt the read context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @param die the DIE to read from.
>   ///
> @@ -13009,7 +12193,7 @@ build_enum_underlying_type(read_context& ctxt,
>   ///
>   /// @return the built enum_type_decl or NULL if it could not be built.
>   static enum_type_decl_sptr
> -build_enum_type(read_context&	ctxt,
> +build_enum_type(reader&	rdr,
>   		Dwarf_Die*	die,
>   		scope_decl*	scope,
>   		size_t		where_offset,
> @@ -13025,7 +12209,7 @@ build_enum_type(read_context&	ctxt,
>   
>     string name, linkage_name;
>     location loc;
> -  die_loc_and_name(ctxt, die, loc, name, linkage_name);
> +  die_loc_and_name(rdr, die, loc, name, linkage_name);
>   
>     bool is_anonymous = false;
>     // If the enum is anonymous, let's give it a name.
> @@ -13040,7 +12224,7 @@ build_enum_type(read_context&	ctxt,
>   	name = build_internal_anonymous_die_name(name, s);
>       }
>   
> -  bool use_odr = ctxt.odr_is_relevant(die);
> +  bool use_odr = rdr.odr_is_relevant(die);
>     // If the type has location, then associate it to its
>     // representation.  This way, all occurences of types with the same
>     // representation (name) and location can be later detected as being
> @@ -13051,10 +12235,10 @@ build_enum_type(read_context&	ctxt,
>         if (use_odr)
>   	{
>   	  if (enum_type_decl_sptr pre_existing_enum =
> -	      is_enum_type(ctxt.lookup_artifact_from_die(die)))
> +	      is_enum_type(rdr.lookup_artifact_from_die(die)))
>   	    result = pre_existing_enum;
>   	}
> -      else if (corpus_sptr corp = ctxt.should_reuse_type_from_corpus_group())
> +      else if (corpus_sptr corp = rdr.should_reuse_type_from_corpus_group())
>   	{
>   	  if (loc)
>   	    result = lookup_enum_type_per_location(loc.expand(), *corp);
> @@ -13062,14 +12246,14 @@ build_enum_type(read_context&	ctxt,
>         else if (loc)
>   	{
>   	  if (enum_type_decl_sptr pre_existing_enum =
> -	      is_enum_type(ctxt.lookup_artifact_from_die(die)))
> +	      is_enum_type(rdr.lookup_artifact_from_die(die)))
>   	    if (pre_existing_enum->get_location() == loc)
>   	      result = pre_existing_enum;
>   	}
>   
>         if (result)
>   	{
> -	  ctxt.associate_die_to_type(die, result, where_offset);
> +	  rdr.associate_die_to_type(die, result, where_offset);
>   	  return result;
>   	}
>       }
> @@ -13095,10 +12279,10 @@ build_enum_type(read_context&	ctxt,
>   
>   	  string n, m;
>   	  location l;
> -	  die_loc_and_name(ctxt, &child, l, n, m);
> +	  die_loc_and_name(rdr, &child, l, n, m);
>   	  uint64_t val = 0;
>   	  die_unsigned_constant_attribute(&child, DW_AT_const_value, val);
> -	  enms.push_back(enum_type_decl::enumerator(ctxt.env(), n, val));
> +	  enms.push_back(enum_type_decl::enumerator(n, val));
>   	}
>         while (dwarf_siblingof(&child, &child) == 0);
>       }
> @@ -13108,7 +12292,7 @@ build_enum_type(read_context&	ctxt,
>     // sole purpose is to be passed to the constructor of the
>     // enum_type_decl type.
>     type_decl_sptr t =
> -    build_enum_underlying_type(ctxt, name, size,
> +    build_enum_underlying_type(rdr, name, size,
>   			       enum_underlying_type_is_anonymous);
>     t->set_is_declaration_only(is_declaration_only);
>   
> @@ -13116,9 +12300,9 @@ build_enum_type(read_context&	ctxt,
>     result->set_is_anonymous(is_anonymous);
>     result->set_is_declaration_only(is_declaration_only);
>     result->set_is_artificial(is_artificial);
> -  ctxt.associate_die_to_type(die, result, where_offset);
> +  rdr.associate_die_to_type(die, result, where_offset);
>   
> -  ctxt.maybe_schedule_declaration_only_enum_for_resolution(result);
> +  rdr.maybe_schedule_declaration_only_enum_for_resolution(result);
>   
>     return result;
>   }
> @@ -13135,12 +12319,12 @@ build_enum_type(read_context&	ctxt,
>   ///
>   /// @param klass the @ref class_or_union that @p f belongs to.
>   ///
> -/// @param ctxt the context used to read the ELF/DWARF information.
> +/// @param rdr the context used to read the ELF/DWARF information.
>   static void
>   finish_member_function_reading(Dwarf_Die*			die,
>   			       const function_decl_sptr&	f,
>   			       const class_or_union_sptr	klass,
> -			       read_context&			ctxt)
> +			       reader&			rdr)
>   {
>     ABG_ASSERT(klass);
>   
> @@ -13237,7 +12421,7 @@ finish_member_function_reading(Dwarf_Die*			die,
>         //
>         // Let's thus schedule this function for a later fixup pass
>         // (performed by
> -      // read_context::fixup_functions_with_no_symbols()) that will
> +      // reader::fixup_functions_with_no_symbols()) that will
>         // set its underlying symbol.
>         //
>         // Note that if the underying symbol is encountered later in the
> @@ -13246,7 +12430,7 @@ finish_member_function_reading(Dwarf_Die*			die,
>         // de-schedule this function wrt fixup pass.
>         Dwarf_Off die_offset = dwarf_dieoffset(die);
>         die_function_decl_map_type &fns_with_no_symbol =
> -	ctxt.die_function_decl_with_no_symbol_map();
> +	rdr.die_function_decl_with_no_symbol_map();
>         die_function_decl_map_type::const_iterator i =
>   	fns_with_no_symbol.find(die_offset);
>         if (i == fns_with_no_symbol.end())
> @@ -13260,7 +12444,7 @@ finish_member_function_reading(Dwarf_Die*			die,
>   /// then read those extra attributes and update the internal
>   /// representation.
>   ///
> -/// @param ctxt the read context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @param die the function DIE to consider.
>   ///
> @@ -13271,12 +12455,12 @@ finish_member_function_reading(Dwarf_Die*			die,
>   ///
>   /// @return the updated function  representation.
>   static function_decl_sptr
> -maybe_finish_function_decl_reading(read_context&		ctxt,
> +maybe_finish_function_decl_reading(reader&		rdr,
>   				   Dwarf_Die*			die,
>   				   size_t			where_offset,
>   				   const function_decl_sptr&	existing_fn)
>   {
> -  function_decl_sptr result = build_function_decl(ctxt, die,
> +  function_decl_sptr result = build_function_decl(rdr, die,
>   						  where_offset,
>   						  existing_fn);
>   
> @@ -13305,7 +12489,7 @@ lookup_class_or_typedef_from_corpus(scope_decl* scope, const string& type_name)
>   ///
>   /// The type being looked for has the same name as a given DIE.
>   ///
> -/// @param ctxt the reading context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @param die the DIE which has the same name as the type we are
>   /// looking for.
> @@ -13317,7 +12501,7 @@ lookup_class_or_typedef_from_corpus(scope_decl* scope, const string& type_name)
>   ///
>   /// @return the type found.
>   static type_base_sptr
> -lookup_class_or_typedef_from_corpus(read_context& ctxt,
> +lookup_class_or_typedef_from_corpus(reader& rdr,
>   				    Dwarf_Die* die,
>   				    bool called_for_public_decl,
>   				    size_t where_offset)
> @@ -13329,7 +12513,7 @@ lookup_class_or_typedef_from_corpus(read_context& ctxt,
>     if (class_name.empty())
>       return class_decl_sptr();
>   
> -  scope_decl_sptr scope = get_scope_for_die(ctxt, die,
> +  scope_decl_sptr scope = get_scope_for_die(rdr, die,
>   					    called_for_public_decl,
>   					    where_offset);
>     if (scope)
> @@ -13392,7 +12576,7 @@ lookup_class_typedef_or_enum_type_from_corpus(Dwarf_Die* die,
>   /// Test if a DIE represents a function that is a member of a given
>   /// class type.
>   ///
> -/// @param ctxt the reading context.
> +/// @param rdr the DWARF reader.
>   ///
>   /// @param function_die the DIE of the function to consider.
>   ///
> @@ -13404,11 +12588,11 @@ lookup_class_typedef_or_enum_type_from_corpus(Dwarf_Die* die,
>   /// function of @p class_type, iff @p function_die is for a member
>   /// function of @p class_type.
>   static method_decl_sptr
> -is_function_for_die_a_member_of_class(read_context& ctxt,
> +is_function_for_die_a_member_of_class(reader& rdr,
>   				      Dwarf_Die* function_die,
>   				      const class_or_union_sptr& class_type)
>   {
> -  type_or_decl_base_sptr artifact = ctxt.lookup_artifact_from_die(function_die);
> +  type_or_decl_base_sptr artifact = rdr.lookup_artifact_from_die(function_die);
>   
>     if (!artifact)
>       return method_decl_sptr();
> @@ -13443,7 +12627,7 @@ is_function_for_die_a_member_of_class(read_context& ctxt,
>   /// new member function that is not already present in the class then
>   /// add that new member function to the class.
>   ///
> -/// @param ctxt the reading context.
> +/// @param rdr the DWARF reader.
>   ///
>   /// @param function_die the DIE of the potential member function to
>   /// consider.
> @@ -13457,17 +12641,17 @@ is_function_for_die_a_member_of_class(read_context& ctxt,
>   ///
>   /// @return the method decl representing the member function.
>   static method_decl_sptr
> -add_or_update_member_function(read_context& ctxt,
> +add_or_update_member_function(reader& rdr,
>   			      Dwarf_Die* function_die,
>   			      const class_or_union_sptr& class_type,
>   			      bool called_from_public_decl,
>   			      size_t where_offset)
>   {
>     method_decl_sptr method =
> -    is_function_for_die_a_member_of_class(ctxt, function_die, class_type);
> +    is_function_for_die_a_member_of_class(rdr, function_die, class_type);
>   
>     if (!method)
> -    method = is_method_decl(build_ir_node_from_die(ctxt, function_die,
> +    method = is_method_decl(build_ir_node_from_die(rdr, function_die,
>   						   class_type.get(),
>   						   called_from_public_decl,
>   						   where_offset));
> @@ -13476,7 +12660,7 @@ add_or_update_member_function(read_context& ctxt,
>   
>     finish_member_function_reading(function_die,
>   				 is_function_decl(method),
> -				 class_type, ctxt);
> +				 class_type, rdr);
>     return method;
>   }
>   
> @@ -13491,7 +12675,7 @@ add_or_update_member_function(read_context& ctxt,
>   /// class_decl node with data members, member functions and other
>   /// properties coming from the DIE.
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param die the DIE to read information from.  Must be either a
>   /// DW_TAG_structure_type or a DW_TAG_class_type.
> @@ -13517,7 +12701,7 @@ add_or_update_member_function(read_context& ctxt,
>   ///
>   /// @return the resulting class_type.
>   static class_decl_sptr
> -add_or_update_class_type(read_context&	 ctxt,
> +add_or_update_class_type(reader&	 rdr,
>   			 Dwarf_Die*	 die,
>   			 scope_decl*	 scope,
>   			 bool		 is_struct,
> @@ -13530,7 +12714,7 @@ add_or_update_class_type(read_context&	 ctxt,
>     if (!die)
>       return result;
>   
> -  const die_source source = ctxt.get_die_source(die);
> +  const die_source source = rdr.get_die_source(die);
>   
>     unsigned tag = dwarf_tag(die);
>   
> @@ -13539,8 +12723,8 @@ add_or_update_class_type(read_context&	 ctxt,
>   
>     {
>       die_class_or_union_map_type::const_iterator i =
> -      ctxt.die_wip_classes_map(source).find(dwarf_dieoffset(die));
> -    if (i != ctxt.die_wip_classes_map(source).end())
> +      rdr.die_wip_classes_map(source).find(dwarf_dieoffset(die));
> +    if (i != rdr.die_wip_classes_map(source).end())
>         {
>   	class_decl_sptr class_type = is_class_type(i->second);
>   	ABG_ASSERT(class_type);
> @@ -13550,7 +12734,7 @@ add_or_update_class_type(read_context&	 ctxt,
>   
>     string name, linkage_name;
>     location loc;
> -  die_loc_and_name(ctxt, die, loc, name, linkage_name);
> +  die_loc_and_name(rdr, die, loc, name, linkage_name);
>   
>     bool is_anonymous = false;
>     if (name.empty())
> @@ -13568,7 +12752,7 @@ add_or_update_class_type(read_context&	 ctxt,
>   
>     if (!is_anonymous)
>       {
> -      if (corpus_sptr corp = ctxt.should_reuse_type_from_corpus_group())
> +      if (corpus_sptr corp = rdr.should_reuse_type_from_corpus_group())
>   	{
>   	  if (loc)
>   	    // TODO: if there is only one class defined in the corpus
> @@ -13588,7 +12772,7 @@ add_or_update_class_type(read_context&	 ctxt,
>   		  || (!result->get_is_declaration_only()
>   		      && is_declaration_only)))
>   	    {
> -	      ctxt.associate_die_to_type(die, result, where_offset);
> +	      rdr.associate_die_to_type(die, result, where_offset);
>   	      return result;
>   	    }
>   	  else
> @@ -13606,7 +12790,7 @@ add_or_update_class_type(read_context&	 ctxt,
>     // when they do have a naming typedef.
>     if (!is_anonymous)
>       if (class_decl_sptr pre_existing_class =
> -	is_class_type(ctxt.lookup_type_artifact_from_die(die)))
> +	is_class_type(rdr.lookup_type_artifact_from_die(die)))
>         klass = pre_existing_class;
>   
>     uint64_t size = 0;
> @@ -13628,7 +12812,7 @@ add_or_update_class_type(read_context&	 ctxt,
>       }
>     else
>       {
> -      result.reset(new class_decl(ctxt.env(), name, size,
> +      result.reset(new class_decl(rdr.env(), name, size,
>   				  /*alignment=*/0, is_struct, loc,
>   				  decl_base::VISIBILITY_DEFAULT,
>   				  is_anonymous));
> @@ -13670,16 +12854,16 @@ add_or_update_class_type(read_context&	 ctxt,
>   
>     result->set_is_artificial(is_artificial);
>   
> -  ctxt.associate_die_to_type(die, result, where_offset);
> +  rdr.associate_die_to_type(die, result, where_offset);
>   
> -  ctxt.maybe_schedule_declaration_only_class_for_resolution(result);
> +  rdr.maybe_schedule_declaration_only_class_for_resolution(result);
>   
>     if (!has_child)
>       // TODO: set the access specifier for the declaration-only class
>       // here.
>       return result;
>   
> -  ctxt.die_wip_classes_map(source)[dwarf_dieoffset(die)] = result;
> +  rdr.die_wip_classes_map(source)[dwarf_dieoffset(die)] = result;
>   
>     bool is_incomplete_type = false;
>     if (is_declaration_only && size == 0 && has_child)
> @@ -13693,13 +12877,13 @@ add_or_update_class_type(read_context&	 ctxt,
>       // referred to by a pointer.  If we later encounter a definition
>       // for this decl-only class type, then this decl-only class will
>       // be resolved to it by the code in
> -    // read_context::resolve_declaration_only_classes.
> +    // reader::resolve_declaration_only_classes.
>       is_incomplete_type = true;
>   
>     scope_decl_sptr scop =
>       dynamic_pointer_cast<scope_decl>(res);
>     ABG_ASSERT(scop);
> -  ctxt.scope_stack().push(scop.get());
> +  rdr.scope_stack().push(scop.get());
>   
>     if (has_child && !is_incomplete_type)
>       {
> @@ -13722,12 +12906,12 @@ add_or_update_class_type(read_context&	 ctxt,
>   
>   	      type_base_sptr base_type;
>   	      if (!(base_type =
> -		    lookup_class_or_typedef_from_corpus(ctxt, &type_die,
> +		    lookup_class_or_typedef_from_corpus(rdr, &type_die,
>   							called_from_public_decl,
>   							where_offset)))
>   		{
>   		  base_type =
> -		    is_type(build_ir_node_from_die(ctxt, &type_die,
> +		    is_type(build_ir_node_from_die(rdr, &type_die,
>   						   called_from_public_decl,
>   						   where_offset));
>   		}
> @@ -13747,14 +12931,14 @@ add_or_update_class_type(read_context&	 ctxt,
>   	      bool is_virt= die_is_virtual(&child);
>   	      int64_t offset = 0;
>   	      bool is_offset_present =
> -		die_member_offset(ctxt, &child, offset);
> +		die_member_offset(rdr, &child, offset);
>   
>   	      class_decl::base_spec_sptr base(new class_decl::base_spec
>   					      (b, access,
>   					       is_offset_present ? offset : -1,
>   					       is_virt));
>   	      if (b->get_is_declaration_only())
> -		ABG_ASSERT(ctxt.is_decl_only_class_scheduled_for_resolution(b));
> +		ABG_ASSERT(rdr.is_decl_only_class_scheduled_for_resolution(b));
>   	      if (result->find_base_class(b->get_qualified_name()))
>   		continue;
>   	      result->add_base_specifier(base);
> @@ -13769,7 +12953,7 @@ add_or_update_class_type(read_context&	 ctxt,
>   
>   	      string n, m;
>   	      location loc;
> -	      die_loc_and_name(ctxt, &child, loc, n, m);
> +	      die_loc_and_name(rdr, &child, loc, n, m);
>   	      /// For now, we skip the hidden vtable pointer.
>   	      /// Currently, we're looking for a member starting with
>   	      /// "_vptr[^0-9a-zA-Z_]", which is what Clang and GCC
> @@ -13786,19 +12970,19 @@ add_or_update_class_type(read_context&	 ctxt,
>   		continue;
>   
>   	      int64_t offset_in_bits = 0;
> -	      bool is_laid_out = die_member_offset(ctxt, &child,
> +	      bool is_laid_out = die_member_offset(rdr, &child,
>   						   offset_in_bits);
>   	      // For now, is_static == !is_laid_out.  When we have
>   	      // templates, we'll try to be more specific.  For now,
>   	      // this approximation should do OK.
>   	      bool is_static = !is_laid_out;
>   
> -	      if (is_static && variable_is_suppressed(ctxt,
> +	      if (is_static && variable_is_suppressed(rdr,
>   						      result.get(),
>   						      &child))
>   		continue;
>   
> -	      decl_base_sptr ty = is_decl(build_ir_node_from_die(ctxt, &type_die,
> +	      decl_base_sptr ty = is_decl(build_ir_node_from_die(rdr, &type_die,
>   								 called_from_public_decl,
>   								 where_offset));
>   	      type_base_sptr t = is_type(ty);
> @@ -13834,18 +13018,18 @@ add_or_update_class_type(read_context&	 ctxt,
>   	      result->add_data_member(dm, access, is_laid_out,
>   				      is_static, offset_in_bits);
>   	      ABG_ASSERT(has_scope(dm));
> -	      ctxt.associate_die_to_decl(&child, dm, where_offset,
> +	      rdr.associate_die_to_decl(&child, dm, where_offset,
>   					 /*associate_by_repr=*/false);
>   	    }
>   	  // Handle member functions;
>   	  else if (tag == DW_TAG_subprogram)
>   	    {
>   	      decl_base_sptr r =
> -		add_or_update_member_function(ctxt, &child, result,
> +		add_or_update_member_function(rdr, &child, result,
>   					      called_from_public_decl,
>   					      where_offset);
>   	      if (function_decl_sptr f = is_function_decl(r))
> -		ctxt.associate_die_to_decl(&child, f, where_offset,
> +		rdr.associate_die_to_decl(&child, f, where_offset,
>   					   /*associate_by_repr=*/true);
>   	    }
>   	  // Handle member types
> @@ -13875,34 +13059,34 @@ add_or_update_class_type(read_context&	 ctxt,
>   		   && !lookup_class_typedef_or_enum_type_from_corpus
>   		   (&child, anonymous_member_type_index, result.get()))
>   		  || !result->find_member_type(die_name(&child)))
> -		build_ir_node_from_die(ctxt, &child, result.get(),
> +		build_ir_node_from_die(rdr, &child, result.get(),
>   				       called_from_public_decl,
>   				       where_offset);
>   	    }
>   	} while (dwarf_siblingof(&child, &child) == 0);
>       }
>   
> -  ctxt.scope_stack().pop();
> +  rdr.scope_stack().pop();
>   
>     {
>       die_class_or_union_map_type::const_iterator i =
> -      ctxt.die_wip_classes_map(source).find(dwarf_dieoffset(die));
> -    if (i != ctxt.die_wip_classes_map(source).end())
> +      rdr.die_wip_classes_map(source).find(dwarf_dieoffset(die));
> +    if (i != rdr.die_wip_classes_map(source).end())
>         {
>   	if (is_member_type(i->second))
>   	  set_member_access_specifier(res,
>   				      get_member_access_specifier(i->second));
> -	ctxt.die_wip_classes_map(source).erase(i);
> +	rdr.die_wip_classes_map(source).erase(i);
>         }
>     }
>   
> -  ctxt.maybe_schedule_declaration_only_class_for_resolution(result);
> +  rdr.maybe_schedule_declaration_only_class_for_resolution(result);
>     return result;
>   }
>   
>   /// Build an @ref union_decl from a DW_TAG_union_type DIE.
>   ///
> -/// @param ctxt the read context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @param die the DIE to read from.
>   ///
> @@ -13925,7 +13109,7 @@ add_or_update_class_type(read_context&	 ctxt,
>   ///
>   /// @return the resulting @ref union_decl type.
>   static union_decl_sptr
> -add_or_update_union_type(read_context&	 ctxt,
> +add_or_update_union_type(reader&	 rdr,
>   			 Dwarf_Die*	 die,
>   			 scope_decl*	 scope,
>   			 union_decl_sptr union_type,
> @@ -13942,11 +13126,11 @@ add_or_update_union_type(read_context&	 ctxt,
>     if (tag != DW_TAG_union_type)
>       return result;
>   
> -  const die_source source = ctxt.get_die_source(die);
> +  const die_source source = rdr.get_die_source(die);
>     {
>       die_class_or_union_map_type::const_iterator i =
> -      ctxt.die_wip_classes_map(source).find(dwarf_dieoffset(die));
> -    if (i != ctxt.die_wip_classes_map(source).end())
> +      rdr.die_wip_classes_map(source).find(dwarf_dieoffset(die));
> +    if (i != rdr.die_wip_classes_map(source).end())
>         {
>   	union_decl_sptr u = is_union_type(i->second);
>   	ABG_ASSERT(u);
> @@ -13956,7 +13140,7 @@ add_or_update_union_type(read_context&	 ctxt,
>   
>     string name, linkage_name;
>     location loc;
> -  die_loc_and_name(ctxt, die, loc, name, linkage_name);
> +  die_loc_and_name(rdr, die, loc, name, linkage_name);
>   
>     bool is_anonymous = false;
>     if (name.empty())
> @@ -13979,7 +13163,7 @@ add_or_update_union_type(read_context&	 ctxt,
>   
>     if (!is_anonymous)
>       {
> -      if (corpus_sptr corp = ctxt.should_reuse_type_from_corpus_group())
> +      if (corpus_sptr corp = rdr.should_reuse_type_from_corpus_group())
>   	{
>   	  if (loc)
>   	    result = lookup_union_type_per_location(loc.expand(), *corp);
> @@ -13988,7 +13172,7 @@ add_or_update_union_type(read_context&	 ctxt,
>   
>   	  if (result)
>   	    {
> -	      ctxt.associate_die_to_type(die, result, where_offset);
> +	      rdr.associate_die_to_type(die, result, where_offset);
>   	      return result;
>   	    }
>   	}
> @@ -14001,7 +13185,7 @@ add_or_update_union_type(read_context&	 ctxt,
>     // a naming typedef.
>     if (!is_anonymous)
>       if (union_decl_sptr pre_existing_union =
> -	is_union_type(ctxt.lookup_artifact_from_die(die)))
> +	is_union_type(rdr.lookup_artifact_from_die(die)))
>         union_type = pre_existing_union;
>   
>     uint64_t size = 0;
> @@ -14015,7 +13199,7 @@ add_or_update_union_type(read_context&	 ctxt,
>       }
>     else
>       {
> -      result.reset(new union_decl(ctxt.env(), name, size, loc,
> +      result.reset(new union_decl(rdr.env(), name, size, loc,
>   				  decl_base::VISIBILITY_DEFAULT,
>   				  is_anonymous));
>         if (is_declaration_only)
> @@ -14032,23 +13216,23 @@ add_or_update_union_type(read_context&	 ctxt,
>   
>     result->set_is_artificial(is_artificial);
>   
> -  ctxt.associate_die_to_type(die, result, where_offset);
> +  rdr.associate_die_to_type(die, result, where_offset);
>   
>     // TODO: maybe schedule declaration-only union for result like we do
>     // for classes:
> -  // ctxt.maybe_schedule_declaration_only_class_for_resolution(result);
> +  // rdr.maybe_schedule_declaration_only_class_for_resolution(result);
>   
>     Dwarf_Die child;
>     bool has_child = (dwarf_child(die, &child) == 0);
>     if (!has_child)
>       return result;
>   
> -  ctxt.die_wip_classes_map(source)[dwarf_dieoffset(die)] = result;
> +  rdr.die_wip_classes_map(source)[dwarf_dieoffset(die)] = result;
>   
>     scope_decl_sptr scop =
>       dynamic_pointer_cast<scope_decl>(result);
>     ABG_ASSERT(scop);
> -  ctxt.scope_stack().push(scop.get());
> +  rdr.scope_stack().push(scop.get());
>   
>     if (has_child)
>       {
> @@ -14064,7 +13248,7 @@ add_or_update_union_type(read_context&	 ctxt,
>   
>   	      string n, m;
>   	      location loc;
> -	      die_loc_and_name(ctxt, &child, loc, n, m);
> +	      die_loc_and_name(rdr, &child, loc, n, m);
>   
>   	      // Because we can be updating an existing union, let's
>   	      // make sure we don't already have a member of the same
> @@ -14075,7 +13259,7 @@ add_or_update_union_type(read_context&	 ctxt,
>   
>   	      ssize_t offset_in_bits = 0;
>   	      decl_base_sptr ty =
> -		is_decl(build_ir_node_from_die(ctxt, &type_die,
> +		is_decl(build_ir_node_from_die(rdr, &type_die,
>   					       called_from_public_decl,
>   					       where_offset));
>   	      type_base_sptr t = is_type(ty);
> @@ -14101,14 +13285,14 @@ add_or_update_union_type(read_context&	 ctxt,
>   				      /*is_static=*/false,
>   				      offset_in_bits);
>   	      ABG_ASSERT(has_scope(dm));
> -	      ctxt.associate_die_to_decl(&child, dm, where_offset,
> +	      rdr.associate_die_to_decl(&child, dm, where_offset,
>   					 /*associate_by_repr=*/false);
>   	    }
>   	  // Handle member functions;
>   	  else if (tag == DW_TAG_subprogram)
>   	    {
>   	      decl_base_sptr r =
> -		is_decl(build_ir_node_from_die(ctxt, &child,
> +		is_decl(build_ir_node_from_die(rdr, &child,
>   					       result.get(),
>   					       called_from_public_decl,
>   					       where_offset));
> @@ -14118,31 +13302,31 @@ add_or_update_union_type(read_context&	 ctxt,
>   	      function_decl_sptr f = dynamic_pointer_cast<function_decl>(r);
>   	      ABG_ASSERT(f);
>   
> -	      finish_member_function_reading(&child, f, result, ctxt);
> +	      finish_member_function_reading(&child, f, result, rdr);
>   
> -	      ctxt.associate_die_to_decl(&child, f, where_offset,
> +	      rdr.associate_die_to_decl(&child, f, where_offset,
>   					 /*associate_by_repr=*/false);
>   	    }
>   	  // Handle member types
>   	  else if (die_is_type(&child))
>   	    decl_base_sptr td =
> -	      is_decl(build_ir_node_from_die(ctxt, &child, result.get(),
> +	      is_decl(build_ir_node_from_die(rdr, &child, result.get(),
>   					     called_from_public_decl,
>   					     where_offset));
>   	} while (dwarf_siblingof(&child, &child) == 0);
>       }
>   
> -  ctxt.scope_stack().pop();
> +  rdr.scope_stack().pop();
>   
>     {
>       die_class_or_union_map_type::const_iterator i =
> -      ctxt.die_wip_classes_map(source).find(dwarf_dieoffset(die));
> -    if (i != ctxt.die_wip_classes_map(source).end())
> +      rdr.die_wip_classes_map(source).find(dwarf_dieoffset(die));
> +    if (i != rdr.die_wip_classes_map(source).end())
>         {
>   	if (is_member_type(i->second))
>   	  set_member_access_specifier(result,
>   				      get_member_access_specifier(i->second));
> -	ctxt.die_wip_classes_map(source).erase(i);
> +	rdr.die_wip_classes_map(source).erase(i);
>         }
>     }
>   
> @@ -14152,7 +13336,7 @@ add_or_update_union_type(read_context&	 ctxt,
>   /// build a qualified type from a DW_TAG_const_type,
>   /// DW_TAG_volatile_type or DW_TAG_restrict_type DIE.
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param die the input DIE to read from.
>   ///
> @@ -14167,7 +13351,7 @@ add_or_update_union_type(read_context&	 ctxt,
>   ///
>   /// @return the resulting qualified_type_def.
>   static type_base_sptr
> -build_qualified_type(read_context&	ctxt,
> +build_qualified_type(reader&	rdr,
>   		     Dwarf_Die*	die,
>   		     bool		called_from_public_decl,
>   		     size_t		where_offset)
> @@ -14189,10 +13373,10 @@ build_qualified_type(read_context&	ctxt,
>       // So, if no DW_AT_type is present, then this means (if we are
>       // looking at a debug info emitted by GCC) that we are looking
>       // at a qualified void type.
> -    utype_decl = build_ir_node_for_void_type(ctxt);
> +    utype_decl = build_ir_node_for_void_type(rdr);
>   
>     if (!utype_decl)
> -    utype_decl = is_decl(build_ir_node_from_die(ctxt, &underlying_type_die,
> +    utype_decl = is_decl(build_ir_node_from_die(rdr, &underlying_type_die,
>   						called_from_public_decl,
>   						where_offset));
>     if (!utype_decl)
> @@ -14200,10 +13384,10 @@ build_qualified_type(read_context&	ctxt,
>   
>     // The call to build_ir_node_from_die() could have triggered the
>     // creation of the type for this DIE.  In that case, just return it.
> -  if (type_base_sptr t = ctxt.lookup_type_from_die(die))
> +  if (type_base_sptr t = rdr.lookup_type_from_die(die))
>       {
>         result = t;
> -      ctxt.associate_die_to_type(die, result, where_offset);
> +      rdr.associate_die_to_type(die, result, where_offset);
>         return result;
>       }
>   
> @@ -14223,7 +13407,7 @@ build_qualified_type(read_context&	ctxt,
>     if (!result)
>       result.reset(new qualified_type_def(utype, qual, location()));
>   
> -  ctxt.associate_die_to_type(die, result, where_offset);
> +  rdr.associate_die_to_type(die, result, where_offset);
>   
>     return result;
>   }
> @@ -14239,22 +13423,22 @@ build_qualified_type(read_context&	ctxt,
>   ///
>   /// @param t the type node to be scheduled for canonicalization.
>   ///
> -/// @param ctxt the contexter of the reader to use.
> +/// @param rdr the DWARF reader to use.
>   static void
>   schedule_array_tree_for_late_canonicalization(const type_base_sptr& t,
> -					      read_context &ctxt)
> +					      reader &rdr)
>   {
>     if (typedef_decl_sptr type = is_typedef(t))
>       {
>         schedule_array_tree_for_late_canonicalization(type->get_underlying_type(),
> -						    ctxt);
> -      ctxt.schedule_type_for_late_canonicalization(t);
> +						    rdr);
> +      rdr.schedule_type_for_late_canonicalization(t);
>       }
>     else if (qualified_type_def_sptr type = is_qualified_type(t))
>       {
>         schedule_array_tree_for_late_canonicalization(type->get_underlying_type(),
> -						    ctxt);
> -      ctxt.schedule_type_for_late_canonicalization(t);
> +						    rdr);
> +      rdr.schedule_type_for_late_canonicalization(t);
>       }
>     else if (array_type_def_sptr type = is_array_type(t))
>       {
> @@ -14264,13 +13448,13 @@ schedule_array_tree_for_late_canonicalization(const type_base_sptr& t,
>   	   ++i)
>   	{
>   	  if (!(*i)->get_scope())
> -	    add_decl_to_scope(*i, ctxt.cur_transl_unit()->get_global_scope());
> -	  ctxt.schedule_type_for_late_canonicalization(*i);
> +	    add_decl_to_scope(*i, rdr.cur_transl_unit()->get_global_scope());
> +	  rdr.schedule_type_for_late_canonicalization(*i);
>   
>   	}
>         schedule_array_tree_for_late_canonicalization(type->get_element_type(),
> -						    ctxt);
> -      ctxt.schedule_type_for_late_canonicalization(type);
> +						    rdr);
> +      rdr.schedule_type_for_late_canonicalization(type);
>       }
>   }
>   
> @@ -14286,12 +13470,12 @@ schedule_array_tree_for_late_canonicalization(const type_base_sptr& t,
>   ///
>   /// @param t the type to strip const qualification from.
>   ///
> -/// @param ctxt the @ref read_context to use.
> +/// @param rdr the @ref reader to use.
>   ///
>   /// @return the stripped type or just return @p t.
>   static decl_base_sptr
>   maybe_strip_qualification(const qualified_type_def_sptr t,
> -			  read_context &ctxt)
> +			  reader &rdr)
>   {
>     if (!t)
>       return t;
> @@ -14313,7 +13497,7 @@ maybe_strip_qualification(const qualified_type_def_sptr t,
>   	  scope = array->get_scope();
>   	  ABG_ASSERT(scope);
>   	  array = is_array_type(clone_array_tree(array));
> -	  schedule_array_tree_for_late_canonicalization(array, ctxt);
> +	  schedule_array_tree_for_late_canonicalization(array, rdr);
>   	  add_decl_to_scope(array, scope);
>   	  t->set_underlying_type(array);
>   	  u = t->get_underlying_type();
> @@ -14324,7 +13508,7 @@ maybe_strip_qualification(const qualified_type_def_sptr t,
>   	  ABG_ASSERT(scope);
>   	  typedef_decl_sptr typdef =
>   	    is_typedef(clone_array_tree(is_typedef(u)));
> -	  schedule_array_tree_for_late_canonicalization(typdef, ctxt);
> +	  schedule_array_tree_for_late_canonicalization(typdef, rdr);
>   	  ABG_ASSERT(typdef);
>   	  add_decl_to_scope(typdef, scope);
>   	  t->set_underlying_type(typdef);
> @@ -14358,7 +13542,7 @@ maybe_strip_qualification(const qualified_type_def_sptr t,
>   	  strip_redundant_quals_from_underyling_types(qual_type);
>   	  add_decl_to_scope(qual_type, is_decl(element_type)->get_scope());
>   	  array->set_element_type(qual_type);
> -	  ctxt.schedule_type_for_late_canonicalization(is_type(qual_type));
> +	  rdr.schedule_type_for_late_canonicalization(is_type(qual_type));
>   	  result = is_decl(u);
>   	}
>       }
> @@ -14368,7 +13552,7 @@ maybe_strip_qualification(const qualified_type_def_sptr t,
>   
>   /// Build a pointer type from a DW_TAG_pointer_type DIE.
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param die the DIE to read information from.
>   ///
> @@ -14383,7 +13567,7 @@ maybe_strip_qualification(const qualified_type_def_sptr t,
>   ///
>   /// @return the resulting pointer to pointer_type_def.
>   static pointer_type_def_sptr
> -build_pointer_type_def(read_context&	ctxt,
> +build_pointer_type_def(reader&	rdr,
>   		       Dwarf_Die*	die,
>   		       bool		called_from_public_decl,
>   		       size_t		where_offset)
> @@ -14403,12 +13587,12 @@ build_pointer_type_def(read_context&	ctxt,
>     if (!die_die_attribute(die, DW_AT_type, underlying_type_die))
>       // If the DW_AT_type attribute is missing, that means we are
>       // looking at a pointer to "void".
> -    utype_decl = build_ir_node_for_void_type(ctxt);
> +    utype_decl = build_ir_node_for_void_type(rdr);
>     else
>       has_underlying_type_die = true;
>   
>     if (!utype_decl && has_underlying_type_die)
> -    utype_decl = build_ir_node_from_die(ctxt, &underlying_type_die,
> +    utype_decl = build_ir_node_from_die(rdr, &underlying_type_die,
>   					called_from_public_decl,
>   					where_offset);
>     if (!utype_decl)
> @@ -14416,7 +13600,7 @@ build_pointer_type_def(read_context&	ctxt,
>   
>     // The call to build_ir_node_from_die() could have triggered the
>     // creation of the type for this DIE.  In that case, just return it.
> -  if (type_base_sptr t = ctxt.lookup_type_from_die(die))
> +  if (type_base_sptr t = rdr.lookup_type_from_die(die))
>       {
>         result = is_pointer_type(t);
>         ABG_ASSERT(result);
> @@ -14429,7 +13613,7 @@ build_pointer_type_def(read_context&	ctxt,
>     // if the DIE for the pointer type doesn't have a byte_size
>     // attribute then we assume the size of the pointer is the address
>     // size of the current translation unit.
> -  uint64_t size = ctxt.cur_transl_unit()->get_address_size();
> +  uint64_t size = rdr.cur_transl_unit()->get_address_size();
>     if (die_unsigned_constant_attribute(die, DW_AT_byte_size, size))
>       // The size as expressed by DW_AT_byte_size is in byte, so let's
>       // convert it to bits.
> @@ -14437,19 +13621,19 @@ build_pointer_type_def(read_context&	ctxt,
>   
>     // And the size of the pointer must be the same as the address size
>     // of the current translation unit.
> -  ABG_ASSERT((size_t) ctxt.cur_transl_unit()->get_address_size() == size);
> +  ABG_ASSERT((size_t) rdr.cur_transl_unit()->get_address_size() == size);
>   
>     result.reset(new pointer_type_def(utype, size, /*alignment=*/0, location()));
>     ABG_ASSERT(result->get_pointed_to_type());
>   
> -  ctxt.associate_die_to_type(die, result, where_offset);
> +  rdr.associate_die_to_type(die, result, where_offset);
>     return result;
>   }
>   
>   /// Build a reference type from either a DW_TAG_reference_type or
>   /// DW_TAG_rvalue_reference_type DIE.
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param die the DIE to read from.
>   ///
> @@ -14464,7 +13648,7 @@ build_pointer_type_def(read_context&	ctxt,
>   ///
>   /// @return a pointer to the resulting reference_type_def.
>   static reference_type_def_sptr
> -build_reference_type(read_context&	ctxt,
> +build_reference_type(reader&	rdr,
>   		     Dwarf_Die*	die,
>   		     bool		called_from_public_decl,
>   		     size_t		where_offset)
> @@ -14484,7 +13668,7 @@ build_reference_type(read_context&	ctxt,
>       return result;
>   
>     type_or_decl_base_sptr utype_decl =
> -    build_ir_node_from_die(ctxt, &underlying_type_die,
> +    build_ir_node_from_die(rdr, &underlying_type_die,
>   			   called_from_public_decl,
>   			   where_offset);
>     if (!utype_decl)
> @@ -14492,7 +13676,7 @@ build_reference_type(read_context&	ctxt,
>   
>     // The call to build_ir_node_from_die() could have triggered the
>     // creation of the type for this DIE.  In that case, just return it.
> -  if (type_base_sptr t = ctxt.lookup_type_from_die(die))
> +  if (type_base_sptr t = rdr.lookup_type_from_die(die))
>       {
>         result = is_reference_type(t);
>         ABG_ASSERT(result);
> @@ -14505,29 +13689,29 @@ build_reference_type(read_context&	ctxt,
>     // if the DIE for the reference type doesn't have a byte_size
>     // attribute then we assume the size of the reference is the address
>     // size of the current translation unit.
> -  uint64_t size = ctxt.cur_transl_unit()->get_address_size();
> +  uint64_t size = rdr.cur_transl_unit()->get_address_size();
>     if (die_unsigned_constant_attribute(die, DW_AT_byte_size, size))
>       size *= 8;
>   
>     // And the size of the pointer must be the same as the address size
>     // of the current translation unit.
> -  ABG_ASSERT((size_t) ctxt.cur_transl_unit()->get_address_size() == size);
> +  ABG_ASSERT((size_t) rdr.cur_transl_unit()->get_address_size() == size);
>   
>     bool is_lvalue = tag == DW_TAG_reference_type;
>   
>     result.reset(new reference_type_def(utype, is_lvalue, size,
>   				      /*alignment=*/0,
>   				      location()));
> -  if (corpus_sptr corp = ctxt.current_corpus())
> +  if (corpus_sptr corp = rdr.corpus())
>       if (reference_type_def_sptr t = lookup_reference_type(*result, *corp))
>         result = t;
> -  ctxt.associate_die_to_type(die, result, where_offset);
> +  rdr.associate_die_to_type(die, result, where_offset);
>     return result;
>   }
>   
>   /// Build a subroutine type from a DW_TAG_subroutine_type DIE.
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param die the DIE to read from.
>   ///
> @@ -14542,7 +13726,7 @@ build_reference_type(read_context&	ctxt,
>   ///
>   /// @return a pointer to the resulting function_type_sptr.
>   static function_type_sptr
> -build_function_type(read_context&	ctxt,
> +build_function_type(reader&	rdr,
>   		    Dwarf_Die*		die,
>   		    class_or_union_sptr is_method,
>   		    size_t		where_offset)
> @@ -14555,12 +13739,12 @@ build_function_type(read_context&	ctxt,
>     ABG_ASSERT(dwarf_tag(die) == DW_TAG_subroutine_type
>   	     || dwarf_tag(die) == DW_TAG_subprogram);
>   
> -  const die_source source = ctxt.get_die_source(die);
> +  const die_source source = rdr.get_die_source(die);
>   
>     {
>       size_t off = dwarf_dieoffset(die);
> -    auto i = ctxt.die_wip_function_types_map(source).find(off);
> -    if (i != ctxt.die_wip_function_types_map(source).end())
> +    auto i = rdr.die_wip_function_types_map(source).find(off);
> +    if (i != rdr.die_wip_function_types_map(source).end())
>         {
>   	function_type_sptr fn_type = is_function_type(i->second);
>   	ABG_ASSERT(fn_type);
> @@ -14570,21 +13754,21 @@ build_function_type(read_context&	ctxt,
>   
>     decl_base_sptr type_decl;
>   
> -  translation_unit_sptr tu = ctxt.cur_transl_unit();
> +  translation_unit_sptr tu = rdr.cur_transl_unit();
>     ABG_ASSERT(tu);
>   
>     /// If, inside the current translation unit, we've already seen a
>     /// function type with the same text representation, then reuse that
>     /// one instead.
> -  if (type_base_sptr t = ctxt.lookup_fn_type_from_die_repr_per_tu(die))
> +  if (type_base_sptr t = rdr.lookup_fn_type_from_die_repr_per_tu(die))
>       {
>         result = is_function_type(t);
>         ABG_ASSERT(result);
> -      ctxt.associate_die_to_type(die, result, where_offset);
> +      rdr.associate_die_to_type(die, result, where_offset);
>         return result;
>       }
>   
> -  bool odr_is_relevant = ctxt.odr_is_relevant(die);
> +  bool odr_is_relevant = rdr.odr_is_relevant(die);
>     if (odr_is_relevant)
>       {
>         // So we can rely on the One Definition Rule to say that if
> @@ -14595,9 +13779,9 @@ build_function_type(read_context&	ctxt,
>         // representation as the function type 'die', then it's the same
>         // type as the one denoted by 'die'.
>         if (function_type_sptr fn_type =
> -	  is_function_type(ctxt.lookup_type_artifact_from_die(die)))
> +	  is_function_type(rdr.lookup_type_artifact_from_die(die)))
>   	{
> -	  ctxt.associate_die_to_type(die, fn_type, where_offset);
> +	  rdr.associate_die_to_type(die, fn_type, where_offset);
>   	  return fn_type;
>   	}
>       }
> @@ -14610,7 +13794,7 @@ build_function_type(read_context&	ctxt,
>     Dwarf_Die object_pointer_die;
>     Dwarf_Die class_type_die;
>     bool has_this_parm_die =
> -    die_function_type_is_method_type(ctxt, die, where_offset,
> +    die_function_type_is_method_type(rdr, die, where_offset,
>   				     object_pointer_die,
>   				     class_type_die,
>   				     is_static);
> @@ -14628,7 +13812,7 @@ build_function_type(read_context&	ctxt,
>   	  // by DIE was *NOT* a member function.  But now we know it's
>   	  // a member function.  Let's take that into account.
>   	  class_or_union_sptr klass_type =
> -	    is_class_or_union_type(build_ir_node_from_die(ctxt, &class_type_die,
> +	    is_class_or_union_type(build_ir_node_from_die(rdr, &class_type_die,
>   							  /*called_from_pub_decl=*/true,
>   							  where_offset));
>   	  ABG_ASSERT(klass_type);
> @@ -14645,20 +13829,20 @@ build_function_type(read_context&	ctxt,
>   	       ? new method_type(is_method, is_const,
>   				 tu->get_address_size(),
>   				 /*alignment=*/0)
> -	       : new function_type(ctxt.env(), tu->get_address_size(),
> +	       : new function_type(rdr.env(), tu->get_address_size(),
>   				   /*alignment=*/0));
> -  ctxt.associate_die_to_type(die, result, where_offset);
> -  ctxt.die_wip_function_types_map(source)[dwarf_dieoffset(die)] = result;
> +  rdr.associate_die_to_type(die, result, where_offset);
> +  rdr.die_wip_function_types_map(source)[dwarf_dieoffset(die)] = result;
>   
>     type_base_sptr return_type;
>     Dwarf_Die ret_type_die;
>     if (die_die_attribute(die, DW_AT_type, ret_type_die))
>       return_type =
> -      is_type(build_ir_node_from_die(ctxt, &ret_type_die,
> +      is_type(build_ir_node_from_die(rdr, &ret_type_die,
>   				     /*called_from_public_decl=*/true,
>   				     where_offset));
>     if (!return_type)
> -    return_type = is_type(build_ir_node_for_void_type(ctxt));
> +    return_type = is_type(build_ir_node_for_void_type(rdr));
>     result->set_return_type(return_type);
>   
>     Dwarf_Die child;
> @@ -14673,7 +13857,7 @@ build_function_type(read_context&	ctxt,
>   	    // This is a "normal" function parameter.
>   	    string name, linkage_name;
>   	    location loc;
> -	    die_loc_and_name(ctxt, &child, loc, name, linkage_name);
> +	    die_loc_and_name(rdr, &child, loc, name, linkage_name);
>   	    if (!tools_utils::string_is_ascii_identifier(name))
>   	      // Sometimes, bogus compiler emit names that are
>   	      // non-ascii garbage.  Let's just ditch that for now.
> @@ -14683,7 +13867,7 @@ build_function_type(read_context&	ctxt,
>   	    Dwarf_Die parm_type_die;
>   	    if (die_die_attribute(&child, DW_AT_type, parm_type_die))
>   	      parm_type =
> -		is_type(build_ir_node_from_die(ctxt, &parm_type_die,
> +		is_type(build_ir_node_from_die(rdr, &parm_type_die,
>   					       /*called_from_public_decl=*/true,
>   					       where_offset));
>   	    if (!parm_type)
> @@ -14698,10 +13882,9 @@ build_function_type(read_context&	ctxt,
>   	  {
>   	    // This is a variadic function parameter.
>   	    bool is_artificial = die_is_artificial(&child);
> -	    ir::environment* env = ctxt.env();
> -	    ABG_ASSERT(env);
> +
>   	    type_base_sptr parm_type =
> -	      is_type(build_ir_node_for_variadic_parameter_type(ctxt));
> +	      is_type(build_ir_node_for_variadic_parameter_type(rdr));
>   	    function_decl::parameter_sptr p
>   	      (new function_decl::parameter(parm_type,
>   					    /*name=*/"",
> @@ -14726,23 +13909,23 @@ build_function_type(read_context&	ctxt,
>   
>     result->set_is_artificial(true);
>   
> -  ctxt.associate_die_repr_to_fn_type_per_tu(die, result);
> +  rdr.associate_die_repr_to_fn_type_per_tu(die, result);
>   
>     {
>       die_function_type_map_type::const_iterator i =
> -      ctxt.die_wip_function_types_map(source).
> +      rdr.die_wip_function_types_map(source).
>         find(dwarf_dieoffset(die));
> -    if (i != ctxt.die_wip_function_types_map(source).end())
> -      ctxt.die_wip_function_types_map(source).erase(i);
> +    if (i != rdr.die_wip_function_types_map(source).end())
> +      rdr.die_wip_function_types_map(source).erase(i);
>     }
>   
> -  maybe_canonicalize_type(result, ctxt);
> +  maybe_canonicalize_type(result, rdr);
>     return result;
>   }
>   
>   /// Build a subrange type from a DW_TAG_subrange_type.
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param die the DIE to read from.
>   ///
> @@ -14763,7 +13946,7 @@ build_function_type(read_context&	ctxt,
>   /// @return the newly built instance of @ref
>   /// array_type_def::subrange_type, or nil if no type could be built.
>   static array_type_def::subrange_sptr
> -build_subrange_type(read_context&	ctxt,
> +build_subrange_type(reader&	rdr,
>   		    const Dwarf_Die*		die,
>   		    size_t		where_offset,
>   		    bool		associate_type_to_die)
> @@ -14786,7 +13969,7 @@ build_subrange_type(read_context&	ctxt,
>     bool is_signed = false;
>     if (die_die_attribute(die, DW_AT_type, underlying_type_die))
>       underlying_type =
> -      is_type(build_ir_node_from_die(ctxt,
> +      is_type(build_ir_node_from_die(rdr,
>   				     &underlying_type_die,
>   				     /*called_from_public_decl=*/true,
>   				     where_offset));
> @@ -14800,7 +13983,7 @@ build_subrange_type(read_context&	ctxt,
>   	  is_signed = (ate == DW_ATE_signed || ate == DW_ATE_signed_char);
>       }
>   
> -  translation_unit::language language = ctxt.cur_transl_unit()->get_language();
> +  translation_unit::language language = rdr.cur_transl_unit()->get_language();
>     array_type_def::subrange_type::bound_value lower_bound =
>       get_default_array_lower_bound(language);
>     array_type_def::subrange_type::bound_value upper_bound;
> @@ -14856,7 +14039,7 @@ build_subrange_type(read_context&	ctxt,
>       }
>   
>     result.reset
> -    (new array_type_def::subrange_type(ctxt.env(),
> +    (new array_type_def::subrange_type(rdr.env(),
>   				       name,
>   				       lower_bound,
>   				       upper_bound,
> @@ -14872,7 +14055,7 @@ build_subrange_type(read_context&	ctxt,
>   			     - result->get_lower_bound() + 1)));
>   
>     if (associate_type_to_die)
> -    ctxt.associate_die_to_type(die, result, where_offset);
> +    rdr.associate_die_to_type(die, result, where_offset);
>   
>     return result;
>   }
> @@ -14881,7 +14064,7 @@ build_subrange_type(read_context&	ctxt,
>   ///
>   /// This is a sub-routine of build_array_type().
>   ///
> -/// @param ctxt the context to read from.
> +/// @param rdr the context to read from.
>   ///
>   /// @param die the DIE of tag DW_TAG_array_type which contains
>   /// children DIEs that represent the sub-ranges.
> @@ -14894,7 +14077,7 @@ build_subrange_type(read_context&	ctxt,
>   /// e.g, DW_TAG_partial_unit that can be included in several places in
>   /// the DIE tree.
>   static void
> -build_subranges_from_array_type_die(read_context&			ctxt,
> +build_subranges_from_array_type_die(reader&			rdr,
>   				    const Dwarf_Die*			die,
>   				    array_type_def::subranges_type&	subranges,
>   				    size_t				where_offset,
> @@ -14916,7 +14099,7 @@ build_subranges_from_array_type_die(read_context&			ctxt,
>   		  // the current type graph and associate it to the
>   		  // DIE it's been created from.
>   		  type_or_decl_base_sptr t =
> -		    build_ir_node_from_die(ctxt, &child,
> +		    build_ir_node_from_die(rdr, &child,
>   					   /*called_from_public_decl=*/true,
>   					   where_offset);
>   		  s = is_subrange_type(t);
> @@ -14925,7 +14108,7 @@ build_subranges_from_array_type_die(read_context&			ctxt,
>   		// We are being called to create the type but *NOT*
>   		// add it to the current tyupe tree, *NOR* associate
>   		// it to the DIE it's been created from.
> -		s = build_subrange_type(ctxt, &child,
> +		s = build_subrange_type(rdr, &child,
>   					where_offset,
>   					/*associate_type_to_die=*/false);
>   	      if (s)
> @@ -14938,7 +14121,7 @@ build_subranges_from_array_type_die(read_context&			ctxt,
>   
>   /// Build an array type from a DW_TAG_array_type DIE.
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param die the DIE to read from.
>   ///
> @@ -14953,7 +14136,7 @@ build_subranges_from_array_type_die(read_context&			ctxt,
>   ///
>   /// @return a pointer to the resulting array_type_def.
>   static array_type_def_sptr
> -build_array_type(read_context&	ctxt,
> +build_array_type(reader&	rdr,
>   		 Dwarf_Die*	die,
>   		 bool		called_from_public_decl,
>   		 size_t	where_offset)
> @@ -14971,7 +14154,7 @@ build_array_type(read_context&	ctxt,
>     Dwarf_Die type_die;
>   
>     if (die_die_attribute(die, DW_AT_type, type_die))
> -    type_decl = is_decl(build_ir_node_from_die(ctxt, &type_die,
> +    type_decl = is_decl(build_ir_node_from_die(rdr, &type_die,
>   					       called_from_public_decl,
>   					       where_offset));
>     if (!type_decl)
> @@ -14979,7 +14162,7 @@ build_array_type(read_context&	ctxt,
>   
>     // The call to build_ir_node_from_die() could have triggered the
>     // creation of the type for this DIE.  In that case, just return it.
> -  if (type_base_sptr t = ctxt.lookup_type_from_die(die))
> +  if (type_base_sptr t = rdr.lookup_type_from_die(die))
>       {
>         result = is_array_type(t);
>         ABG_ASSERT(result);
> @@ -14991,7 +14174,7 @@ build_array_type(read_context&	ctxt,
>   
>     array_type_def::subranges_type subranges;
>   
> -  build_subranges_from_array_type_die(ctxt, die, subranges, where_offset);
> +  build_subranges_from_array_type_die(rdr, die, subranges, where_offset);
>   
>     result.reset(new array_type_def(type, subranges, location()));
>   
> @@ -15000,7 +14183,7 @@ build_array_type(read_context&	ctxt,
>   
>   /// Create a typedef_decl from a DW_TAG_typedef DIE.
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param die the DIE to read from.
>   ///
> @@ -15015,7 +14198,7 @@ build_array_type(read_context&	ctxt,
>   ///
>   /// @return the newly created typedef_decl.
>   static typedef_decl_sptr
> -build_typedef_type(read_context&	ctxt,
> +build_typedef_type(reader&	rdr,
>   		   Dwarf_Die*		die,
>   		   bool		called_from_public_decl,
>   		   size_t		where_offset)
> @@ -15031,9 +14214,9 @@ build_typedef_type(read_context&	ctxt,
>   
>     string name, linkage_name;
>     location loc;
> -  die_loc_and_name(ctxt, die, loc, name, linkage_name);
> +  die_loc_and_name(rdr, die, loc, name, linkage_name);
>   
> -  if (corpus_sptr corp = ctxt.should_reuse_type_from_corpus_group())
> +  if (corpus_sptr corp = rdr.should_reuse_type_from_corpus_group())
>       if (loc)
>         result = lookup_typedef_type_per_location(loc.expand(), *corp);
>   
> @@ -15044,11 +14227,11 @@ build_typedef_type(read_context&	ctxt,
>         if (!die_die_attribute(die, DW_AT_type, underlying_type_die))
>   	// A typedef DIE with no underlying type means a typedef to
>   	// void type.
> -	utype = ctxt.env()->get_void_type();
> +	utype = rdr.env().get_void_type();
>   
>         if (!utype)
>   	utype =
> -	  is_type(build_ir_node_from_die(ctxt,
> +	  is_type(build_ir_node_from_die(rdr,
>   					 &underlying_type_die,
>   					 called_from_public_decl,
>   					 where_offset));
> @@ -15069,20 +14252,20 @@ build_typedef_type(read_context&	ctxt,
>   	}
>       }
>   
> -  ctxt.associate_die_to_type(die, result, where_offset);
> +  rdr.associate_die_to_type(die, result, where_offset);
>   
>     return result;
>   }
>   
>   /// Build a @ref var_decl out of a DW_TAG_variable DIE if the variable
>   /// denoted by the DIE is not suppressed by a suppression
> -/// specification associated to the current read context.
> +/// specification associated to the current DWARF reader.
>   ///
>   /// Note that if a member variable declaration with the same name as
>   /// the name of the DIE we are looking at exists, this function returns
>   /// that existing variable declaration.
>   ///
> -/// @param ctxt the read context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @param die the DIE representing the variable we are looking at.
>   ///
> @@ -15103,7 +14286,7 @@ build_typedef_type(read_context&	ctxt,
>   /// @return a pointer to the newly created var_decl.  If the var_decl
>   /// could not be built, this function returns NULL.
>   static var_decl_sptr
> -build_or_get_var_decl_if_not_suppressed(read_context&	ctxt,
> +build_or_get_var_decl_if_not_suppressed(reader&	rdr,
>   					scope_decl	*scope,
>   					Dwarf_Die	*die,
>   					size_t	where_offset,
> @@ -15111,7 +14294,7 @@ build_or_get_var_decl_if_not_suppressed(read_context&	ctxt,
>   					bool is_required_decl_spec)
>   {
>     var_decl_sptr var;
> -  if (variable_is_suppressed(ctxt, scope, die, is_required_decl_spec))
> +  if (variable_is_suppressed(rdr, scope, die, is_required_decl_spec))
>       return var;
>   
>     if (class_decl* class_type = is_class_type(scope))
> @@ -15121,13 +14304,13 @@ build_or_get_var_decl_if_not_suppressed(read_context&	ctxt,
>   	if ((var = class_type->find_data_member(var_name)))
>   	  return var;
>       }
> -  var = build_var_decl(ctxt, die, where_offset, result);
> +  var = build_var_decl(rdr, die, where_offset, result);
>     return var;
>   }
>   
>   /// Build a @ref var_decl out of a DW_TAG_variable DIE.
>   ///
> -/// @param ctxt the read context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @param die the DIE representing the variable we are looking at.
>   ///
> @@ -15144,7 +14327,7 @@ build_or_get_var_decl_if_not_suppressed(read_context&	ctxt,
>   /// @return a pointer to the newly created var_decl.  If the var_decl
>   /// could not be built, this function returns NULL.
>   static var_decl_sptr
> -build_var_decl(read_context&	ctxt,
> +build_var_decl(reader&	rdr,
>   	       Dwarf_Die	*die,
>   	       size_t		where_offset,
>   	       var_decl_sptr	result)
> @@ -15163,7 +14346,7 @@ build_var_decl(read_context&	ctxt,
>     if (die_die_attribute(die, DW_AT_type, type_die))
>       {
>         decl_base_sptr ty =
> -	is_decl(build_ir_node_from_die(ctxt, &type_die,
> +	is_decl(build_ir_node_from_die(rdr, &type_die,
>   				       /*called_from_public_decl=*/true,
>   				       where_offset));
>         if (!ty)
> @@ -15177,7 +14360,7 @@ build_var_decl(read_context&	ctxt,
>   
>     string name, linkage_name;
>     location loc;
> -  die_loc_and_name(ctxt, die, loc, name, linkage_name);
> +  die_loc_and_name(rdr, die, loc, name, linkage_name);
>   
>     if (!result)
>       result.reset(new var_decl(name, type, loc, linkage_name));
> @@ -15197,13 +14380,15 @@ build_var_decl(read_context&	ctxt,
>       {
>         elf_symbol_sptr var_sym;
>         Dwarf_Addr      var_addr;
> -      if (ctxt.get_variable_address(die, var_addr))
> +
> +      if (rdr.get_variable_address(die, var_addr))
>   	{
> -	  ctxt.symtab()->update_main_symbol(var_addr,
> -					    result->get_linkage_name().empty()
> -					      ? result->get_name()
> -					      : result->get_linkage_name());
> -	  var_sym = ctxt.variable_symbol_is_exported(var_addr);
> +	  rdr.symtab()->
> +	    update_main_symbol(var_addr,
> +			       result->get_linkage_name().empty()
> +			       ? result->get_name()
> +			       : result->get_linkage_name());
> +	  var_sym = rdr.variable_symbol_is_exported(var_addr);
>   	}
>   
>         if (var_sym)
> @@ -15229,7 +14414,7 @@ build_var_decl(read_context&	ctxt,
>   /// Note that a non-member function which symbol is not exported is
>   /// also suppressed.
>   ///
> -/// @param ctxt the ELF/DWARF reading content of interest.
> +/// @param rdr the ELF/DWARF reading content of interest.
>   ///
>   /// @param scope of the scope of the function.
>   ///
> @@ -15239,9 +14424,9 @@ build_var_decl(read_context&	ctxt,
>   /// a declaration-only DIE.
>   ///
>   /// @return true iff @p function_die is suppressed by at least one
> -/// suppression specification attached to the @p ctxt.
> +/// suppression specification attached to the @p rdr.
>   static bool
> -function_is_suppressed(const read_context& ctxt,
> +function_is_suppressed(const reader& rdr,
>   		       const scope_decl* scope,
>   		       Dwarf_Die *function_die,
>   		       bool is_declaration_only)
> @@ -15252,7 +14437,7 @@ function_is_suppressed(const read_context& ctxt,
>   
>     string fname = die_string_attribute(function_die, DW_AT_name);
>     string flinkage_name = die_linkage_name(function_die);
> -  if (flinkage_name.empty() && ctxt.die_is_in_c(function_die))
> +  if (flinkage_name.empty() && rdr.die_is_in_c(function_die))
>       flinkage_name = fname;
>     string qualified_name = build_qualified_name(scope, fname);
>   
> @@ -15263,13 +14448,14 @@ function_is_suppressed(const read_context& ctxt,
>     // symbol, by default, it's not suppressed.  Unless we are asked to
>     // drop undefined symbols too.
>     if (!is_class_type(scope)
> -      && (!is_declaration_only || ctxt.drop_undefined_syms()))
> +      && (!is_declaration_only || rdr.drop_undefined_syms()))
>       {
>         Dwarf_Addr fn_addr;
> -      if (!ctxt.get_function_address(function_die, fn_addr))
> +      if (!rdr.get_function_address(function_die, fn_addr))
>   	return true;
>   
> -      elf_symbol_sptr symbol = ctxt.function_symbol_is_exported(fn_addr);
> +      elf_symbol_sptr symbol =
> +	rdr.function_symbol_is_exported(fn_addr);
>         if (!symbol)
>   	return true;
>         if (!symbol->is_suppressed())
> @@ -15286,14 +14472,13 @@ function_is_suppressed(const read_context& ctxt,
>   	    return false;
>       }
>   
> -  return suppr::function_is_suppressed(ctxt, qualified_name,
> -				       flinkage_name,
> +  return suppr::is_function_suppressed(rdr, qualified_name, flinkage_name,
>   				       /*require_drop_property=*/true);
>   }
>   
>   /// Build a @ref function_decl out of a DW_TAG_subprogram DIE if the
>   /// function denoted by the DIE is not suppressed by a suppression
> -/// specification associated to the current read context.
> +/// specification associated to the current DWARF reader.
>   ///
>   /// Note that if a member function declaration with the same signature
>   /// (pretty representation) as one of the DIE we are looking at
> @@ -15309,7 +14494,7 @@ function_is_suppressed(const read_context& ctxt,
>   /// accordingly.  This is done to support "updating" a function_decl
>   /// IR with properties scathered across several DIEs.
>   ///
> -/// @param ctxt the read context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @param scope the scope of the function we are looking at.
>   ///
> @@ -15332,7 +14517,7 @@ function_is_suppressed(const read_context& ctxt,
>   /// @return a pointer to the newly created var_decl.  If the var_decl
>   /// could not be built, this function returns NULL.
>   static function_decl_sptr
> -build_or_get_fn_decl_if_not_suppressed(read_context&	  ctxt,
> +build_or_get_fn_decl_if_not_suppressed(reader&	  rdr,
>   				       scope_decl	  *scope,
>   				       Dwarf_Die	  *fn_die,
>   				       size_t		  where_offset,
> @@ -15340,7 +14525,7 @@ build_or_get_fn_decl_if_not_suppressed(read_context&	  ctxt,
>   				       function_decl_sptr result)
>   {
>     function_decl_sptr fn;
> -  if (function_is_suppressed(ctxt, scope, fn_die, is_declaration_only))
> +  if (function_is_suppressed(rdr, scope, fn_die, is_declaration_only))
>       return fn;
>   
>     string name = die_name(fn_die);
> @@ -15364,11 +14549,11 @@ build_or_get_fn_decl_if_not_suppressed(read_context&	  ctxt,
>     // symbols.  So re-using C++ destructors like that can lead to us
>     // missing some destructors.
>     if (!result && (!(is_dtor && is_virtual)))
> -    if ((fn = is_function_decl(ctxt.lookup_artifact_from_die(fn_die))))
> +    if ((fn = is_function_decl(rdr.lookup_artifact_from_die(fn_die))))
>         {
> -	fn = maybe_finish_function_decl_reading(ctxt, fn_die, where_offset, fn);
> -	ctxt.associate_die_to_decl(fn_die, fn, /*do_associate_by_repr=*/true);
> -	ctxt.associate_die_to_type(fn_die, fn->get_type(), where_offset);
> +	fn = maybe_finish_function_decl_reading(rdr, fn_die, where_offset, fn);
> +	rdr.associate_die_to_decl(fn_die, fn, /*do_associate_by_repr=*/true);
> +	rdr.associate_die_to_type(fn_die, fn->get_type(), where_offset);
>   	return fn;
>         }
>   
> @@ -15387,7 +14572,7 @@ build_or_get_fn_decl_if_not_suppressed(read_context&	  ctxt,
>       // any associated symbol will be dropped on the floor by
>       // potential_member_fn_should_be_dropped.  So let's build or a new
>       // function IR or complete the existing partial IR.
> -    fn = build_function_decl(ctxt, fn_die, where_offset, result);
> +    fn = build_function_decl(rdr, fn_die, where_offset, result);
>   
>     return fn;
>   }
> @@ -15396,7 +14581,7 @@ build_or_get_fn_decl_if_not_suppressed(read_context&	  ctxt,
>   /// suppressed by any of the suppression specifications associated to
>   /// a given context of ELF/DWARF reading.
>   ///
> -/// @param ctxt the ELF/DWARF reading content of interest.
> +/// @param rdr the ELF/DWARF reading content of interest.
>   ///
>   /// @param scope of the scope of the variable.
>   ///
> @@ -15407,9 +14592,9 @@ build_or_get_fn_decl_if_not_suppressed(read_context&	  ctxt,
>   /// specification for a concrete variable being built.
>   ///
>   /// @return true iff @p variable_die is suppressed by at least one
> -/// suppression specification attached to the @p ctxt.
> +/// suppression specification attached to the @p rdr.
>   static bool
> -variable_is_suppressed(const read_context& ctxt,
> +variable_is_suppressed(const reader& rdr,
>   		       const scope_decl* scope,
>   		       Dwarf_Die *variable_die,
>   		       bool is_required_decl_spec)
> @@ -15421,7 +14606,7 @@ variable_is_suppressed(const read_context& ctxt,
>   
>     string name = die_string_attribute(variable_die, DW_AT_name);
>     string linkage_name = die_linkage_name(variable_die);
> -  if (linkage_name.empty() && ctxt.die_is_in_c(variable_die))
> +  if (linkage_name.empty() && rdr.die_is_in_c(variable_die))
>       linkage_name = name;
>     string qualified_name = build_qualified_name(scope, name);
>   
> @@ -15433,10 +14618,11 @@ variable_is_suppressed(const read_context& ctxt,
>     if (!is_class_type(scope) && !is_required_decl_spec)
>       {
>         Dwarf_Addr var_addr = 0;
> -      if (!ctxt.get_variable_address(variable_die, var_addr))
> +      if (!rdr.get_variable_address(variable_die, var_addr))
>   	return true;
>   
> -      elf_symbol_sptr symbol = ctxt.variable_symbol_is_exported(var_addr);
> +      elf_symbol_sptr symbol =
> +	rdr.variable_symbol_is_exported(var_addr);
>         if (!symbol)
>   	return true;
>         if (!symbol->is_suppressed())
> @@ -15453,16 +14639,17 @@ variable_is_suppressed(const read_context& ctxt,
>   	    return false;
>       }
>   
> -  return suppr::variable_is_suppressed(ctxt, qualified_name,
> +  return suppr::is_variable_suppressed(rdr,
> +				       qualified_name,
>   				       linkage_name,
>   				       /*require_drop_property=*/true);
>   }
>   
>   /// Test if a type (designated by a given DIE) in a given scope is
>   /// suppressed by the suppression specifications that are associated
> -/// to a given read context.
> +/// to a given DWARF reader.
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param scope of the scope of the type DIE to consider.
>   ///
> @@ -15475,9 +14662,9 @@ variable_is_suppressed(const read_context& ctxt,
>   ///
>   /// @return true iff the type designated by the DIE @p type_die, in
>   /// the scope @p scope is suppressed by at the suppression
> -/// specifications associated to the current read context.
> +/// specifications associated to the current DWARF reader.
>   static bool
> -type_is_suppressed(const read_context& ctxt,
> +type_is_suppressed(const reader& rdr,
>   		   const scope_decl* scope,
>   		   Dwarf_Die *type_die,
>   		   bool &type_is_private)
> @@ -15491,10 +14678,11 @@ type_is_suppressed(const read_context& ctxt,
>   
>     string type_name, linkage_name;
>     location type_location;
> -  die_loc_and_name(ctxt, type_die, type_location, type_name, linkage_name);
> +  die_loc_and_name(rdr, type_die, type_location, type_name, linkage_name);
>     string qualified_name = build_qualified_name(scope, type_name);
>   
> -  return suppr::type_is_suppressed(ctxt, qualified_name,
> +  return suppr::is_type_suppressed(rdr,
> +				   qualified_name,
>   				   type_location,
>   				   type_is_private,
>   				   /*require_drop_property=*/true);
> @@ -15502,9 +14690,9 @@ type_is_suppressed(const read_context& ctxt,
>   
>   /// Test if a type (designated by a given DIE) in a given scope is
>   /// suppressed by the suppression specifications that are associated
> -/// to a given read context.
> +/// to a given DWARF reader.
>   ///
> -/// @param ctxt the read context to consider.
> +/// @param rdr the DWARF reader to consider.
>   ///
>   /// @param scope of the scope of the type DIE to consider.
>   ///
> @@ -15512,14 +14700,14 @@ type_is_suppressed(const read_context& ctxt,
>   ///
>   /// @return true iff the type designated by the DIE @p type_die, in
>   /// the scope @p scope is suppressed by at the suppression
> -/// specifications associated to the current read context.
> +/// specifications associated to the current DWARF reader.
>   static bool
> -type_is_suppressed(const read_context& ctxt,
> +type_is_suppressed(const reader& rdr,
>   		   const scope_decl* scope,
>   		   Dwarf_Die *type_die)
>   {
>     bool type_is_private = false;
> -  return type_is_suppressed(ctxt, scope, type_die, type_is_private);
> +  return type_is_suppressed(rdr, scope, type_die, type_is_private);
>   }
>   
>   /// Get the opaque version of a type that was suppressed because it's
> @@ -15529,7 +14717,7 @@ type_is_suppressed(const read_context& ctxt,
>   /// version of the type (class, union or enum type) denoted by @p
>   /// type_die.
>   ///
> -/// @param ctxt the read context in use.
> +/// @param rdr the DWARF reader in use.
>   ///
>   /// @param scope the scope of the type die we are looking at.
>   ///
> @@ -15543,7 +14731,7 @@ type_is_suppressed(const read_context& ctxt,
>   /// @return the opaque version of the type denoted by @p type_die or
>   /// nil if no opaque version was found.
>   static type_or_decl_base_sptr
> -get_opaque_version_of_type(read_context	&ctxt,
> +get_opaque_version_of_type(reader	&rdr,
>   			   scope_decl		*scope,
>   			   Dwarf_Die		*type_die,
>   			   size_t		where_offset)
> @@ -15562,7 +14750,7 @@ get_opaque_version_of_type(read_context	&ctxt,
>   
>     string type_name, linkage_name;
>     location type_location;
> -  die_loc_and_name(ctxt, type_die, type_location, type_name, linkage_name);
> +  die_loc_and_name(rdr, type_die, type_location, type_name, linkage_name);
>     if (!type_location)
>       return result;
>   
> @@ -15576,8 +14764,8 @@ get_opaque_version_of_type(read_context	&ctxt,
>     if (tag == DW_TAG_structure_type || tag == DW_TAG_class_type)
>       {
>         string_classes_map::const_iterator i =
> -	ctxt.declaration_only_classes().find(qualified_name);
> -      if (i != ctxt.declaration_only_classes().end())
> +	rdr.declaration_only_classes().find(qualified_name);
> +      if (i != rdr.declaration_only_classes().end())
>   	result = i->second.back();
>   
>         if (!result)
> @@ -15587,7 +14775,7 @@ get_opaque_version_of_type(read_context	&ctxt,
>   	  // opaque type.  So let's build one.
>   	  //
>   	  // TODO: we need to be able to do this for unions too!
> -	  class_decl_sptr klass(new class_decl(ctxt.env(), type_name,
> +	  class_decl_sptr klass(new class_decl(rdr.env(), type_name,
>   					       /*alignment=*/0, /*size=*/0,
>   					       tag == DW_TAG_structure_type,
>   					       type_location,
> @@ -15595,8 +14783,8 @@ get_opaque_version_of_type(read_context	&ctxt,
>   	  klass->set_is_declaration_only(true);
>   	  klass->set_is_artificial(die_is_artificial(type_die));
>   	  add_decl_to_scope(klass, scope);
> -	  ctxt.associate_die_to_type(type_die, klass, where_offset);
> -	  ctxt.maybe_schedule_declaration_only_class_for_resolution(klass);
> +	  rdr.associate_die_to_type(type_die, klass, where_offset);
> +	  rdr.maybe_schedule_declaration_only_class_for_resolution(klass);
>   	  result = klass;
>   	}
>       }
> @@ -15604,8 +14792,8 @@ get_opaque_version_of_type(read_context	&ctxt,
>     if (tag == DW_TAG_enumeration_type)
>       {
>         string_enums_map::const_iterator i =
> -	ctxt.declaration_only_enums().find(qualified_name);
> -      if (i != ctxt.declaration_only_enums().end())
> +	rdr.declaration_only_enums().find(qualified_name);
> +      if (i != rdr.declaration_only_enums().end())
>   	result = i->second.back();
>   
>         if (!result)
> @@ -15614,7 +14802,7 @@ get_opaque_version_of_type(read_context	&ctxt,
>   	  if (die_unsigned_constant_attribute(type_die, DW_AT_byte_size, size))
>   	    size *= 8;
>   	  type_decl_sptr underlying_type =
> -	    build_enum_underlying_type(ctxt, type_name, size,
> +	    build_enum_underlying_type(rdr, type_name, size,
>   				       /*anonymous=*/true);
>   	  enum_type_decl::enumerators enumeratorz;
>   	  enum_type_decl_sptr enum_type (new enum_type_decl(type_name,
> @@ -15639,7 +14827,7 @@ get_opaque_version_of_type(read_context	&ctxt,
>   ///
>   /// @return the newly created symbol.
>   elf_symbol_sptr
> -create_default_fn_sym(const string& sym_name, const environment *env)
> +create_default_fn_sym(const string& sym_name, const environment& env)
>   {
>     elf_symbol::version ver;
>     elf_symbol_sptr result =
> @@ -15658,7 +14846,7 @@ create_default_fn_sym(const string& sym_name, const environment *env)
>   
>   /// Build a @ref function_decl our of a DW_TAG_subprogram DIE.
>   ///
> -/// @param ctxt the read context to use
> +/// @param rdr the DWARF reader to use
>   ///
>   /// @param die the DW_TAG_subprogram DIE to read from.
>   ///
> @@ -15670,7 +14858,7 @@ create_default_fn_sym(const string& sym_name, const environment *env)
>   /// @param called_for_public_decl this is set to true if the function
>   /// was called for a public (function) decl.
>   static function_decl_sptr
> -build_function_decl(read_context&	ctxt,
> +build_function_decl(reader&	rdr,
>   		    Dwarf_Die*		die,
>   		    size_t		where_offset,
>   		    function_decl_sptr	fn)
> @@ -15683,16 +14871,16 @@ build_function_decl(read_context&	ctxt,
>     if (!die_is_public_decl(die))
>       return result;
>   
> -  translation_unit_sptr tu = ctxt.cur_transl_unit();
> +  translation_unit_sptr tu = rdr.cur_transl_unit();
>     ABG_ASSERT(tu);
>   
>     string fname, flinkage_name;
>     location floc;
> -  die_loc_and_name(ctxt, die, floc, fname, flinkage_name);
> +  die_loc_and_name(rdr, die, floc, fname, flinkage_name);
>   
>     size_t is_inline = die_is_declared_inline(die);
>     class_or_union_sptr is_method =
> -    is_class_or_union_type(get_scope_for_die(ctxt, die, true, where_offset));
> +    is_class_or_union_type(get_scope_for_die(rdr, die, true, where_offset));
>   
>     if (result)
>       {
> @@ -15713,12 +14901,12 @@ build_function_decl(read_context&	ctxt,
>       }
>     else
>       {
> -      function_type_sptr fn_type(build_function_type(ctxt, die, is_method,
> +      function_type_sptr fn_type(build_function_type(rdr, die, is_method,
>   						     where_offset));
>         if (!fn_type)
>   	return result;
>   
> -      maybe_canonicalize_type(fn_type, ctxt);
> +      maybe_canonicalize_type(fn_type, rdr);
>   
>         result.reset(is_method
>   		   ? new method_decl(fname, fn_type,
> @@ -15735,16 +14923,17 @@ build_function_decl(read_context&	ctxt,
>       {
>         elf_symbol_sptr fn_sym;
>         Dwarf_Addr      fn_addr;
> -      if (ctxt.get_function_address(die, fn_addr))
> +      if (rdr.get_function_address(die, fn_addr))
>   	{
> -	  ctxt.symtab()->update_main_symbol(fn_addr,
> -					    result->get_linkage_name().empty()
> -					      ? result->get_name()
> -					      : result->get_linkage_name());
> -	  fn_sym = ctxt.function_symbol_is_exported(fn_addr);
> +	  rdr.symtab()->
> +	    update_main_symbol(fn_addr,
> +			       result->get_linkage_name().empty()
> +			       ? result->get_name()
> +			       : result->get_linkage_name());
> +	  fn_sym = rdr.function_symbol_is_exported(fn_addr);
>   	}
>   
> -      if (fn_sym && !ctxt.symbol_already_belongs_to_a_function(fn_sym))
> +      if (fn_sym && !rdr.symbol_already_belongs_to_a_function(fn_sym))
>   	{
>   	  result->set_symbol(fn_sym);
>   	  string linkage_name = result->get_linkage_name();
> @@ -15754,7 +14943,7 @@ build_function_decl(read_context&	ctxt,
>   	}
>       }
>   
> -  ctxt.associate_die_to_type(die, result->get_type(), where_offset);
> +  rdr.associate_die_to_type(die, result->get_type(), where_offset);
>   
>     size_t die_offset = dwarf_dieoffset(die);
>   
> @@ -15767,250 +14956,10 @@ build_function_decl(read_context&	ctxt,
>       // It thus doesn't need any fixup related to elf symbol.  So
>       // remove it from the set of virtual member functions with linkage
>       // names and no elf symbol that need to be fixed up.
> -    ctxt.die_function_decl_with_no_symbol_map().erase(die_offset);
> +    rdr.die_function_decl_with_no_symbol_map().erase(die_offset);
>     return result;
>   }
>   
> -/// Read all @ref abigail::translation_unit possible from the debug info
> -/// accessible through a DWARF Front End Library handle, and stuff
> -/// them into a libabigail ABI Corpus.
> -///
> -/// @param ctxt the read context.
> -///
> -/// @return a pointer to the resulting corpus, or NULL if the corpus
> -/// could not be constructed.
> -static corpus_sptr
> -read_debug_info_into_corpus(read_context& ctxt)
> -{
> -  ctxt.clear_per_corpus_data();
> -  ctxt.current_corpus(std::make_shared<corpus>(ctxt.env(), ctxt.elf_path()));
> -
> -  // First set some mundane properties of the corpus gathered from
> -  // ELF.
> -  ctxt.current_corpus()->set_path(ctxt.elf_path());
> -
> -  corpus::origin origin = corpus::DWARF_ORIGIN;
> -  if (is_linux_kernel(ctxt.elf_handle()))
> -    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
> -  ctxt.current_corpus()->set_origin(origin);
> -
> -  if (origin & corpus::LINUX_KERNEL_BINARY_ORIGIN
> -      && !ctxt.env()->user_set_analyze_exported_interfaces_only())
> -    // So we are looking at the Linux Kernel and the user has not set
> -    // any particular option regarding the amount of types to analyse.
> -    // In that case, we need to only analyze types that are reachable
> -    // from exported interfaces otherwise we get such a massive amount
> -    // of type DIEs to look at that things are just too slow down the
> -    // road.
> -    ctxt.env()->analyze_exported_interfaces_only(true);
> -
> -  ctxt.current_corpus()->set_soname(ctxt.dt_soname());
> -  ctxt.current_corpus()->set_needed(ctxt.dt_needed());
> -  ctxt.current_corpus()->set_architecture_name(ctxt.elf_architecture());
> -  if (corpus_group_sptr group = ctxt.current_corpus_group())
> -    group->add_corpus(ctxt.current_corpus());
> -
> -  // Set symbols information to the corpus.
> -  ctxt.current_corpus()->set_symtab(ctxt.symtab());
> -
> -  // Get out now if no debug info is found.
> -  if (!ctxt.dwarf())
> -    return ctxt.current_corpus();
> -
> -  uint8_t address_size = 0;
> -  size_t header_size = 0;
> -
> -  // Set the set of exported declaration that are defined.
> -  ctxt.exported_decls_builder
> -    (ctxt.current_corpus()->get_exported_decls_builder().get());
> -
> -#ifdef WITH_DEBUG_SELF_COMPARISON
> -  if (ctxt.env()->self_comparison_debug_is_on())
> -    ctxt.env()->set_self_comparison_debug_input(ctxt.current_corpus());
> -#endif
> -
> -  // Walk all the DIEs of the debug info to build a DIE -> parent map
> -  // useful for get_die_parent() to work.
> -  {
> -    tools_utils::timer t;
> -    if (ctxt.do_log())
> -      {
> -	cerr << "building die -> parent maps ...";
> -	t.start();
> -      }
> -
> -    ctxt.build_die_parent_maps();
> -
> -    if (ctxt.do_log())
> -      {
> -	t.stop();
> -	cerr << " DONE@" << ctxt.current_corpus()->get_path()
> -	     << ":"
> -	     << t
> -	     << "\n";
> -      }
> -  }
> -
> -  ctxt.env()->canonicalization_is_done(false);
> -
> -  {
> -    tools_utils::timer t;
> -    if (ctxt.do_log())
> -      {
> -	cerr << "building the libabigail internal representation ...";
> -	t.start();
> -      }
> -    // And now walk all the DIEs again to build the libabigail IR.
> -    Dwarf_Half dwarf_version = 0;
> -    for (Dwarf_Off offset = 0, next_offset = 0;
> -	 (dwarf_next_unit(ctxt.dwarf(), offset, &next_offset, &header_size,
> -			  &dwarf_version, NULL, &address_size, NULL,
> -			  NULL, NULL) == 0);
> -	 offset = next_offset)
> -      {
> -	Dwarf_Off die_offset = offset + header_size;
> -	Dwarf_Die unit;
> -	if (!dwarf_offdie(ctxt.dwarf(), die_offset, &unit)
> -	    || dwarf_tag(&unit) != DW_TAG_compile_unit)
> -	  continue;
> -
> -	ctxt.dwarf_version(dwarf_version);
> -
> -	address_size *= 8;
> -
> -	// Build a translation_unit IR node from cu; note that cu must
> -	// be a DW_TAG_compile_unit die.
> -	translation_unit_sptr ir_node =
> -	  build_translation_unit_and_add_to_ir(ctxt, &unit, address_size);
> -	ABG_ASSERT(ir_node);
> -      }
> -    if (ctxt.do_log())
> -      {
> -	t.stop();
> -	cerr << " DONE@" << ctxt.current_corpus()->get_path()
> -	     << ":"
> -	     << t
> -	     << "\n";
> -
> -	cerr << "Number of aggregate types compared: "
> -	     << ctxt.compare_count_ << "\n"
> -	     << "Number of canonical types propagated: "
> -	     << ctxt.canonical_propagated_count_ << "\n"
> -	     << "Number of cancelled propagated canonical types:"
> -	     << ctxt.cancelled_propagation_count_ << "\n";
> -      }
> -  }
> -
> -  {
> -    tools_utils::timer t;
> -    if (ctxt.do_log())
> -      {
> -	cerr << "resolving declaration only classes ...";
> -	t.start();
> -      }
> -    ctxt.resolve_declaration_only_classes();
> -    if (ctxt.do_log())
> -      {
> -	t.stop();
> -	cerr << " DONE@" << ctxt.current_corpus()->get_path()
> -	     << ":"
> -	     << t
> -	     <<"\n";
> -      }
> -  }
> -
> -  {
> -    tools_utils::timer t;
> -    if (ctxt.do_log())
> -      {
> -	cerr << "resolving declaration only enums ...";
> -	t.start();
> -      }
> -    ctxt.resolve_declaration_only_enums();
> -    if (ctxt.do_log())
> -      {
> -	t.stop();
> -	cerr << " DONE@" << ctxt.current_corpus()->get_path()
> -	     << ":"
> -	     << t
> -	     <<"\n";
> -      }
> -  }
> -
> -  {
> -    tools_utils::timer t;
> -    if (ctxt.do_log())
> -      {
> -	cerr << "fixing up functions with linkage name but "
> -	     << "no advertised underlying symbols ....";
> -	t.start();
> -      }
> -    ctxt.fixup_functions_with_no_symbols();
> -    if (ctxt.do_log())
> -      {
> -	t.stop();
> -	cerr << " DONE@" << ctxt.current_corpus()->get_path()
> -	     <<":"
> -	     << t
> -	     <<"\n";
> -      }
> -  }
> -
> -  /// Now, look at the types that needs to be canonicalized after the
> -  /// translation has been constructed (which is just now) and
> -  /// canonicalize them.
> -  ///
> -  /// These types need to be constructed at the end of the translation
> -  /// unit reading phase because some types are modified by some DIEs
> -  /// even after the principal DIE describing the type has been read;
> -  /// this happens for clones of virtual destructors (for instance) or
> -  /// even for some static data members.  We need to do that for types
> -  /// are in the alternate debug info section and for types that in
> -  /// the main debug info section.
> -  {
> -    tools_utils::timer t;
> -    if (ctxt.do_log())
> -      {
> -	cerr << "perform late type canonicalizing ...\n";
> -	t.start();
> -      }
> -
> -    ctxt.perform_late_type_canonicalizing();
> -    if (ctxt.do_log())
> -      {
> -	t.stop();
> -	cerr << "late type canonicalizing DONE@"
> -	     << ctxt.current_corpus()->get_path()
> -	     << ":"
> -	     << t
> -	     << "\n";
> -      }
> -  }
> -
> -  ctxt.env()->canonicalization_is_done(true);
> -
> -  {
> -    tools_utils::timer t;
> -    if (ctxt.do_log())
> -      {
> -	cerr << "sort functions and variables ...";
> -	t.start();
> -      }
> -    ctxt.current_corpus()->sort_functions();
> -    ctxt.current_corpus()->sort_variables();
> -    if (ctxt.do_log())
> -      {
> -	t.stop();
> -	cerr << " DONE@" << ctxt.current_corpus()->get_path()
> -	     << ":"
> -	     << t
> -	     <<" \n";
> -      }
> -  }
> -
> -  return ctxt.current_corpus();
> -}
> -
>   /// Canonicalize a type if it's suitable for early canonicalizing, or,
>   /// if it's not, schedule it for late canonicalization, after the
>   /// debug info of the current translation unit has been fully read.
> @@ -16024,10 +14973,10 @@ read_debug_info_into_corpus(read_context& ctxt)
>   ///
>   /// @param t the type DIE to consider for canonicalization.
>   ///
> -/// @param ctxt the @ref read_context to use.
> +/// @param rdr the @ref reader to use.
>   static void
>   maybe_canonicalize_type(const type_base_sptr& t,
> -			read_context&	ctxt)
> +			reader&	rdr)
>   {
>     if (!t)
>       return;
> @@ -16049,9 +14998,9 @@ maybe_canonicalize_type(const type_base_sptr& t,
>       // side.  We also delay canonicalization for array and qualified
>       // types because they can be edited (in particular by
>       // maybe_strip_qualification) after they are initially built.
> -    ctxt.schedule_type_for_late_canonicalization(t);
> +    rdr.schedule_type_for_late_canonicalization(t);
>     else if (type_has_non_canonicalized_subtype(t))
> -    ctxt.schedule_type_for_late_canonicalization(t);
> +    rdr.schedule_type_for_late_canonicalization(t);
>     else
>       canonicalize(t);
>   }
> @@ -16121,10 +15070,10 @@ potential_member_fn_should_be_dropped(const function_decl_sptr& fn,
>   }
>   
>   /// Build an IR node from a given DIE and add the node to the current
> -/// IR being build and held in the read_context.  Doing that is called
> +/// IR being build and held in the DWARF reader.  Doing that is called
>   /// "emitting an IR node for the DIE".
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the DWARF reader.
>   ///
>   /// @param die the DIE to consider.
>   ///
> @@ -16153,7 +15102,7 @@ potential_member_fn_should_be_dropped(const function_decl_sptr& fn,
>   ///
>   /// @return the resulting IR node.
>   static type_or_decl_base_sptr
> -build_ir_node_from_die(read_context&	ctxt,
> +build_ir_node_from_die(reader&	rdr,
>   		       Dwarf_Die*	die,
>   		       scope_decl*	scope,
>   		       bool		called_from_public_decl,
> @@ -16170,7 +15119,7 @@ build_ir_node_from_die(read_context&	ctxt,
>   
>     if (!called_from_public_decl)
>       {
> -      if (ctxt.load_all_types() && die_is_type(die))
> +      if (rdr.load_all_types() && die_is_type(die))
>   	/* We were instructed to load debug info for all types,
>   	   included those that are not reachable from a public
>   	   declaration.  So load the debug info for this type.  */;
> @@ -16181,12 +15130,12 @@ build_ir_node_from_die(read_context&	ctxt,
>   	return result;
>       }
>   
> -  const die_source source_of_die = ctxt.get_die_source(die);
> +  const die_source source_of_die = rdr.get_die_source(die);
>   
> -  if ((result = ctxt.lookup_decl_from_die_offset(dwarf_dieoffset(die),
> +  if ((result = rdr.lookup_decl_from_die_offset(dwarf_dieoffset(die),
>   						 source_of_die)))
>       {
> -      if (ctxt.load_all_types())
> +      if (rdr.load_all_types())
>   	if (called_from_public_decl)
>   	  if (type_base_sptr t = is_type(result))
>   	    if (corpus *abi_corpus = scope->get_corpus())
> @@ -16205,10 +15154,10 @@ build_ir_node_from_die(read_context&	ctxt,
>       {
>         // Type DIEs we support.
>       case DW_TAG_base_type:
> -      if (type_decl_sptr t = build_type_decl(ctxt, die, where_offset))
> +      if (type_decl_sptr t = build_type_decl(rdr, die, where_offset))
>   	{
>   	  result =
> -	    add_decl_to_scope(t, ctxt.cur_transl_unit()->get_global_scope());
> +	    add_decl_to_scope(t, rdr.cur_transl_unit()->get_global_scope());
>   	  canonicalize(t);
>   	}
>         break;
> @@ -16219,7 +15168,7 @@ build_ir_node_from_die(read_context&	ctxt,
>   	t = is_typedef(scope->find_member_type(die_name(die)));
>   
>   	if (!t)
> -	  t = build_typedef_type(ctxt, die,
> +	  t = build_typedef_type(rdr, die,
>   				 called_from_public_decl,
>   				 where_offset);
>   
> @@ -16227,7 +15176,7 @@ build_ir_node_from_die(read_context&	ctxt,
>   	if (result)
>   	  {
>   	    maybe_set_member_type_access_specifier(is_decl(result), die);
> -	    maybe_canonicalize_type(t, ctxt);
> +	    maybe_canonicalize_type(t, rdr);
>   	  }
>         }
>         break;
> @@ -16235,15 +15184,15 @@ build_ir_node_from_die(read_context&	ctxt,
>       case DW_TAG_pointer_type:
>         {
>   	pointer_type_def_sptr p =
> -	  build_pointer_type_def(ctxt, die,
> +	  build_pointer_type_def(rdr, die,
>   				 called_from_public_decl,
>   				 where_offset);
>   	if (p)
>   	  {
>   	    result =
> -	      add_decl_to_scope(p, ctxt.cur_transl_unit()->get_global_scope());
> +	      add_decl_to_scope(p, rdr.cur_transl_unit()->get_global_scope());
>   	    ABG_ASSERT(result->get_translation_unit());
> -	    maybe_canonicalize_type(p, ctxt);
> +	    maybe_canonicalize_type(p, rdr);
>   	  }
>         }
>         break;
> @@ -16252,16 +15201,16 @@ build_ir_node_from_die(read_context&	ctxt,
>       case DW_TAG_rvalue_reference_type:
>         {
>   	reference_type_def_sptr r =
> -	  build_reference_type(ctxt, die,
> +	  build_reference_type(rdr, die,
>   			       called_from_public_decl,
>   			       where_offset);
>   	if (r)
>   	  {
>   	    result =
> -	      add_decl_to_scope(r, ctxt.cur_transl_unit()->get_global_scope());
> +	      add_decl_to_scope(r, rdr.cur_transl_unit()->get_global_scope());
>   
> -	    ctxt.associate_die_to_type(die, r, where_offset);
> -	    maybe_canonicalize_type(r, ctxt);
> +	    rdr.associate_die_to_type(die, r, where_offset);
> +	    maybe_canonicalize_type(r, rdr);
>   	  }
>         }
>         break;
> @@ -16271,7 +15220,7 @@ build_ir_node_from_die(read_context&	ctxt,
>       case DW_TAG_restrict_type:
>         {
>   	type_base_sptr q =
> -	  build_qualified_type(ctxt, die,
> +	  build_qualified_type(rdr, die,
>   			       called_from_public_decl,
>   			       where_offset);
>   	if (q)
> @@ -16279,7 +15228,7 @@ build_ir_node_from_die(read_context&	ctxt,
>   	    // Strip some potentially redundant type qualifiers from
>   	    // the qualified type we just built.
>   	    decl_base_sptr d = maybe_strip_qualification(is_qualified_type(q),
> -							 ctxt);
> +							 rdr);
>   	    if (!d)
>   	      d = get_type_declaration(q);
>   	    ABG_ASSERT(d);
> @@ -16287,10 +15236,10 @@ build_ir_node_from_die(read_context&	ctxt,
>   	    // Associate the die to type ty again because 'ty'might be
>   	    // different from 'q', because 'ty' is 'q' possibly
>   	    // stripped from some redundant type qualifier.
> -	    ctxt.associate_die_to_type(die, ty, where_offset);
> +	    rdr.associate_die_to_type(die, ty, where_offset);
>   	    result =
> -	      add_decl_to_scope(d, ctxt.cur_transl_unit()->get_global_scope());
> -	    maybe_canonicalize_type(is_type(result), ctxt);
> +	      add_decl_to_scope(d, rdr.cur_transl_unit()->get_global_scope());
> +	    maybe_canonicalize_type(is_type(result), rdr);
>   	  }
>         }
>         break;
> @@ -16299,7 +15248,7 @@ build_ir_node_from_die(read_context&	ctxt,
>         {
>   	bool type_is_private = false;
>   	bool type_suppressed =
> -	  type_is_suppressed(ctxt, scope, die, type_is_private);
> +	  type_is_suppressed(rdr, scope, die, type_is_private);
>   	if (type_suppressed && type_is_private)
>   	  {
>   	    // The type is suppressed because it's private.  If other
> @@ -16308,19 +15257,19 @@ build_ir_node_from_die(read_context&	ctxt,
>   	    // non-suppressed instances are opaque versions of the
>   	    // suppressed private type.  Lets return one of these opaque
>   	    // types then.
> -	    result = get_opaque_version_of_type(ctxt, scope, die, where_offset);
> -	    maybe_canonicalize_type(is_type(result), ctxt);
> +	    result = get_opaque_version_of_type(rdr, scope, die, where_offset);
> +	    maybe_canonicalize_type(is_type(result), rdr);
>   	  }
>   	else if (!type_suppressed)
>   	  {
> -	    enum_type_decl_sptr e = build_enum_type(ctxt, die, scope,
> +	    enum_type_decl_sptr e = build_enum_type(rdr, die, scope,
>   						    where_offset,
>   						    is_declaration_only);
>   	    result = add_decl_to_scope(e, scope);
>   	    if (result)
>   	      {
>   		maybe_set_member_type_access_specifier(is_decl(result), die);
> -		maybe_canonicalize_type(is_type(result), ctxt);
> +		maybe_canonicalize_type(is_type(result), rdr);
>   	      }
>   	  }
>         }
> @@ -16331,7 +15280,7 @@ build_ir_node_from_die(read_context&	ctxt,
>         {
>   	bool type_is_private = false;
>   	bool type_suppressed=
> -	  type_is_suppressed(ctxt, scope, die, type_is_private);
> +	  type_is_suppressed(rdr, scope, die, type_is_private);
>   
>   	if (type_suppressed && type_is_private)
>   	  {
> @@ -16341,8 +15290,8 @@ build_ir_node_from_die(read_context&	ctxt,
>   	    // non-suppressed instances are opaque versions of the
>   	    // suppressed private type.  Lets return one of these opaque
>   	    // types then.
> -	    result = get_opaque_version_of_type(ctxt, scope, die, where_offset);
> -	    maybe_canonicalize_type(is_type(result), ctxt);
> +	    result = get_opaque_version_of_type(rdr, scope, die, where_offset);
> +	    maybe_canonicalize_type(is_type(result), rdr);
>   	  }
>   	else if (!type_suppressed)
>   	  {
> @@ -16352,12 +15301,12 @@ build_ir_node_from_die(read_context&	ctxt,
>   	    if (die_die_attribute(die, DW_AT_specification, spec_die))
>   	      {
>   		scope_decl_sptr skope =
> -		  get_scope_for_die(ctxt, &spec_die,
> +		  get_scope_for_die(rdr, &spec_die,
>   				    called_from_public_decl,
>   				    where_offset);
>   		ABG_ASSERT(skope);
>   		decl_base_sptr cl =
> -		  is_decl(build_ir_node_from_die(ctxt, &spec_die,
> +		  is_decl(build_ir_node_from_die(rdr, &spec_die,
>   						 skope.get(),
>   						 called_from_public_decl,
>   						 where_offset,
> @@ -16368,7 +15317,7 @@ build_ir_node_from_die(read_context&	ctxt,
>   		ABG_ASSERT(klass);
>   
>   		klass =
> -		  add_or_update_class_type(ctxt, die,
> +		  add_or_update_class_type(rdr, die,
>   					   skope.get(),
>   					   tag == DW_TAG_structure_type,
>   					   klass,
> @@ -16378,7 +15327,7 @@ build_ir_node_from_die(read_context&	ctxt,
>   	      }
>   	    else
>   	      klass =
> -		add_or_update_class_type(ctxt, die, scope,
> +		add_or_update_class_type(rdr, die, scope,
>   					 tag == DW_TAG_structure_type,
>   					 class_decl_sptr(),
>   					 called_from_public_decl,
> @@ -16388,16 +15337,16 @@ build_ir_node_from_die(read_context&	ctxt,
>   	    if (klass)
>   	      {
>   		maybe_set_member_type_access_specifier(klass, die);
> -		maybe_canonicalize_type(klass, ctxt);
> +		maybe_canonicalize_type(klass, rdr);
>   	      }
>   	  }
>         }
>         break;
>       case DW_TAG_union_type:
> -      if (!type_is_suppressed(ctxt, scope, die))
> +      if (!type_is_suppressed(rdr, scope, die))
>   	{
>   	  union_decl_sptr union_type =
> -	    add_or_update_union_type(ctxt, die, scope,
> +	    add_or_update_union_type(rdr, die, scope,
>   				     union_decl_sptr(),
>   				     called_from_public_decl,
>   				     where_offset,
> @@ -16405,7 +15354,7 @@ build_ir_node_from_die(read_context&	ctxt,
>   	  if (union_type)
>   	    {
>   	      maybe_set_member_type_access_specifier(union_type, die);
> -	      maybe_canonicalize_type(union_type, ctxt);
> +	      maybe_canonicalize_type(union_type, rdr);
>   	    }
>   	  result = union_type;
>   	}
> @@ -16414,29 +15363,29 @@ build_ir_node_from_die(read_context&	ctxt,
>         break;
>       case DW_TAG_subroutine_type:
>         {
> -	function_type_sptr f = build_function_type(ctxt, die,
> +	function_type_sptr f = build_function_type(rdr, die,
>   						   class_decl_sptr(),
>   						   where_offset);
>   	if (f)
>   	  {
>   	    result = f;
>   	    result->set_is_artificial(false);
> -	    maybe_canonicalize_type(f, ctxt);
> +	    maybe_canonicalize_type(f, rdr);
>   	  }
>         }
>         break;
>       case DW_TAG_array_type:
>         {
> -	array_type_def_sptr a = build_array_type(ctxt,
> +	array_type_def_sptr a = build_array_type(rdr,
>   						 die,
>   						 called_from_public_decl,
>   						 where_offset);
>   	if (a)
>   	  {
>   	    result =
> -	      add_decl_to_scope(a, ctxt.cur_transl_unit()->get_global_scope());
> -	    ctxt.associate_die_to_type(die, a, where_offset);
> -	    maybe_canonicalize_type(a, ctxt);
> +	      add_decl_to_scope(a, rdr.cur_transl_unit()->get_global_scope());
> +	    rdr.associate_die_to_type(die, a, where_offset);
> +	    maybe_canonicalize_type(a, rdr);
>   	  }
>   	break;
>         }
> @@ -16446,13 +15395,13 @@ build_ir_node_from_die(read_context&	ctxt,
>   	// form" defined in the global namespace of the current
>   	// translation unit, like what is found in Ada.
>   	array_type_def::subrange_sptr s =
> -	  build_subrange_type(ctxt, die, where_offset);
> +	  build_subrange_type(rdr, die, where_offset);
>   	if (s)
>   	  {
>   	    result =
> -	      add_decl_to_scope(s, ctxt.cur_transl_unit()->get_global_scope());
> -	    ctxt.associate_die_to_type(die, s, where_offset);
> -	    maybe_canonicalize_type(s, ctxt);
> +	      add_decl_to_scope(s, rdr.cur_transl_unit()->get_global_scope());
> +	    rdr.associate_die_to_type(die, s, where_offset);
> +	    maybe_canonicalize_type(s, rdr);
>   	  }
>         }
>         break;
> @@ -16480,7 +15429,7 @@ build_ir_node_from_die(read_context&	ctxt,
>   
>       case DW_TAG_namespace:
>       case DW_TAG_module:
> -      result = build_namespace_decl_and_add_to_ir(ctxt, die, where_offset);
> +      result = build_namespace_decl_and_add_to_ir(rdr, die, where_offset);
>         break;
>   
>       case DW_TAG_variable:
> @@ -16490,21 +15439,21 @@ build_ir_node_from_die(read_context&	ctxt,
>   	bool var_is_cloned = false;
>   
>   	if (tag == DW_TAG_member)
> -	  ABG_ASSERT(!is_c_language(ctxt.cur_transl_unit()->get_language()));
> +	  ABG_ASSERT(!is_c_language(rdr.cur_transl_unit()->get_language()));
>   
>   	if (die_die_attribute(die, DW_AT_specification, spec_die, false)
>   	    || (var_is_cloned = die_die_attribute(die, DW_AT_abstract_origin,
>   						  spec_die, false)))
>   	  {
>   	    scope_decl_sptr spec_scope =
> -	      get_scope_for_die(ctxt, &spec_die,
> +	      get_scope_for_die(rdr, &spec_die,
>   				/*called_from_public_decl=*/
> -				die_is_effectively_public_decl(ctxt, die),
> +				die_is_effectively_public_decl(rdr, die),
>   				where_offset);
>   	    if (spec_scope)
>   	      {
>   		decl_base_sptr d =
> -		  is_decl(build_ir_node_from_die(ctxt, &spec_die,
> +		  is_decl(build_ir_node_from_die(rdr, &spec_die,
>   						 spec_scope.get(),
>   						 called_from_public_decl,
>   						 where_offset,
> @@ -16516,26 +15465,26 @@ build_ir_node_from_die(read_context&	ctxt,
>   		      dynamic_pointer_cast<var_decl>(d);
>   		    if (var_is_cloned)
>   		      m = m->clone();
> -		    m = build_var_decl(ctxt, die, where_offset, m);
> +		    m = build_var_decl(rdr, die, where_offset, m);
>   		    if (is_data_member(m))
>   		      {
>   			set_member_is_static(m, true);
> -			ctxt.associate_die_to_decl(die, m, where_offset,
> +			rdr.associate_die_to_decl(die, m, where_offset,
>   						   /*associate_by_repr=*/false);
>   		      }
>   		    else
>   		      {
>   			ABG_ASSERT(has_scope(m));
> -			ctxt.var_decls_to_re_add_to_tree().push_back(m);
> +			rdr.var_decls_to_re_add_to_tree().push_back(m);
>   		      }
>   		    ABG_ASSERT(m->get_scope());
> -		    ctxt.maybe_add_var_to_exported_decls(m.get());
> +		    rdr.maybe_add_var_to_exported_decls(m.get());
>   		    result = m;
>   		  }
>   	      }
>   	  }
>   	else if (var_decl_sptr v =
> -		 build_or_get_var_decl_if_not_suppressed(ctxt, scope, die,
> +		 build_or_get_var_decl_if_not_suppressed(rdr, scope, die,
>   							 where_offset,
>   							 /*result=*/var_decl_sptr(),
>   							 is_required_decl_spec))
> @@ -16545,8 +15494,8 @@ build_ir_node_from_die(read_context&	ctxt,
>   	    v = dynamic_pointer_cast<var_decl>(result);
>   	    ABG_ASSERT(v);
>   	    ABG_ASSERT(v->get_scope());
> -	    ctxt.var_decls_to_re_add_to_tree().push_back(v);
> -	    ctxt.maybe_add_var_to_exported_decls(v.get());
> +	    rdr.var_decls_to_re_add_to_tree().push_back(v);
> +	    rdr.maybe_add_var_to_exported_decls(v.get());
>   	  }
>         }
>         break;
> @@ -16580,7 +15529,7 @@ build_ir_node_from_die(read_context&	ctxt,
>   	    string linkage_name = die_linkage_name(die);
>   	    string spec_linkage_name = die_linkage_name(interface_die);
>   
> -	    interface_scope = get_scope_for_die(ctxt, interface_die,
> +	    interface_scope = get_scope_for_die(rdr, interface_die,
>   						called_from_public_decl,
>   						where_offset);
>   	    if (interface_scope)
> @@ -16591,7 +15540,7 @@ build_ir_node_from_die(read_context&	ctxt,
>   		  d = c->find_member_function_sptr(linkage_name);
>   
>   		if (!d)
> -		  d = is_decl(build_ir_node_from_die(ctxt,
> +		  d = is_decl(build_ir_node_from_die(rdr,
>   						     origin_die,
>   						     interface_scope.get(),
>   						     called_from_public_decl,
> @@ -16612,14 +15561,14 @@ build_ir_node_from_die(read_context&	ctxt,
>   		  }
>   	      }
>   	  }
> -	ctxt.scope_stack().push(scope);
> +	rdr.scope_stack().push(scope);
>   
>   	scope_decl* logical_scope =
>   	  interface_scope
>   	  ? interface_scope.get()
>   	  : scope;
>   
> -	result = build_or_get_fn_decl_if_not_suppressed(ctxt, logical_scope,
> +	result = build_or_get_fn_decl_if_not_suppressed(rdr, logical_scope,
>   							die, where_offset,
>   							is_declaration_only,
>   							fn);
> @@ -16642,18 +15591,18 @@ build_ir_node_from_die(read_context&	ctxt,
>   	    class_decl_sptr klass(static_cast<class_decl*>(logical_scope),
>   				  sptr_utils::noop_deleter());
>   	    ABG_ASSERT(klass);
> -	    finish_member_function_reading(die, fn, klass, ctxt);
> +	    finish_member_function_reading(die, fn, klass, rdr);
>   	  }
>   
>   	if (fn)
>   	  {
> -	    ctxt.maybe_add_fn_to_exported_decls(fn.get());
> -	    ctxt.associate_die_to_decl(die, fn, where_offset,
> +	    rdr.maybe_add_fn_to_exported_decls(fn.get());
> +	    rdr.associate_die_to_decl(die, fn, where_offset,
>   				       /*associate_by_repr=*/false);
> -	    maybe_canonicalize_type(fn->get_type(), ctxt);
> +	    maybe_canonicalize_type(fn->get_type(), rdr);
>   	  }
>   
> -	ctxt.scope_stack().pop();
> +	rdr.scope_stack().pop();
>         }
>         break;
>   
> @@ -16718,11 +15667,11 @@ build_ir_node_from_die(read_context&	ctxt,
>       }
>   
>     if (result && tag != DW_TAG_subroutine_type)
> -    ctxt.associate_die_to_decl(die, is_decl(result), where_offset,
> +    rdr.associate_die_to_decl(die, is_decl(result), where_offset,
>   			       /*associate_by_repr=*/false);
>   
>     if (result)
> -    if (ctxt.load_all_types())
> +    if (rdr.load_all_types())
>         if (called_from_public_decl)
>   	if (type_base_sptr t = is_type(result))
>   	  if (corpus *abi_corpus = scope->get_corpus())
> @@ -16733,48 +15682,48 @@ build_ir_node_from_die(read_context&	ctxt,
>   
>   ///  Build the IR node for a void type.
>   ///
> -///  @param ctxt the read context to use.
> +///  @param rdr the DWARF reader to use.
>   ///
>   ///  @return the void type node.
>   static decl_base_sptr
> -build_ir_node_for_void_type(read_context& ctxt)
> +build_ir_node_for_void_type(reader& rdr)
>   {
> -  ir::environment* env = ctxt.env();
> -  ABG_ASSERT(env);
> -  type_base_sptr t = env->get_void_type();
> +  const environment& env = rdr.env();
> +
> +  type_base_sptr t = env.get_void_type();
>     decl_base_sptr type_declaration = get_type_declaration(t);
>     if (!has_scope(type_declaration))
>       add_decl_to_scope(type_declaration,
> -		      ctxt.cur_transl_unit()->get_global_scope());
> +		      rdr.cur_transl_unit()->get_global_scope());
>     canonicalize(t);
>     return type_declaration;
>   }
>   
>   /// Build the IR node for a variadic parameter type.
>   ///
> -/// @param ctxt the read context to use.
> +/// @param rdr the DWARF reader to use.
>   ///
>   /// @return the variadic parameter type.
>   static decl_base_sptr
> -build_ir_node_for_variadic_parameter_type(read_context &ctxt)
> +build_ir_node_for_variadic_parameter_type(reader &rdr)
>   {
>   
> -  ir::environment* env = ctxt.env();
> -  ABG_ASSERT(env);
> -  type_base_sptr t = env->get_variadic_parameter_type();
> +  const environment& env = rdr.env();
> +
> +  type_base_sptr t = env.get_variadic_parameter_type();
>     decl_base_sptr type_declaration = get_type_declaration(t);
>     if (!has_scope(type_declaration))
>       add_decl_to_scope(type_declaration,
> -		      ctxt.cur_transl_unit()->get_global_scope());
> +		      rdr.cur_transl_unit()->get_global_scope());
>     canonicalize(t);
>     return type_declaration;
>   }
>   
>   /// Build an IR node from a given DIE and add the node to the current
> -/// IR being build and held in the read_context.  Doing that is called
> +/// IR being build and held in the DWARF reader.  Doing that is called
>   /// "emitting an IR node for the DIE".
>   ///
> -/// @param ctxt the read context.
> +/// @param rdr the DWARF reader.
>   ///
>   /// @param die the DIE to consider.
>   ///
> @@ -16793,7 +15742,7 @@ build_ir_node_for_variadic_parameter_type(read_context &ctxt)
>   ///
>   /// @return the resulting IR node.
>   static type_or_decl_base_sptr
> -build_ir_node_from_die(read_context&	ctxt,
> +build_ir_node_from_die(reader&	rdr,
>   		       Dwarf_Die*	die,
>   		       bool		called_from_public_decl,
>   		       size_t		where_offset)
> @@ -16801,10 +15750,10 @@ build_ir_node_from_die(read_context&	ctxt,
>     if (!die)
>       return decl_base_sptr();
>   
> -  if (is_c_language(ctxt.cur_transl_unit()->get_language()))
> +  if (is_c_language(rdr.cur_transl_unit()->get_language()))
>       {
> -      const scope_decl_sptr& scop = ctxt.global_scope();
> -      return build_ir_node_from_die(ctxt, die, scop.get(),
> +      const scope_decl_sptr& scop = rdr.global_scope();
> +      return build_ir_node_from_die(rdr, die, scop.get(),
>   				    called_from_public_decl,
>   				    where_offset,
>                                       true);
> @@ -16819,17 +15768,17 @@ build_ir_node_from_die(read_context&	ctxt,
>     // to it, it'll be dropped on the floor anyway.  Those variable
>     // decls are considered as being "effectively public".
>     bool consider_as_called_from_public_decl =
> -    called_from_public_decl || die_is_effectively_public_decl(ctxt, die);
> -  scope_decl_sptr scope = get_scope_for_die(ctxt, die,
> +    called_from_public_decl || die_is_effectively_public_decl(rdr, die);
> +  scope_decl_sptr scope = get_scope_for_die(rdr, die,
>   					    consider_as_called_from_public_decl,
>   					    where_offset);
> -  return build_ir_node_from_die(ctxt, die, scope.get(),
> +  return build_ir_node_from_die(rdr, die, scope.get(),
>   				called_from_public_decl,
>   				where_offset,
>                                   true);
>   }
>   
> -/// Create a dwarf_reader::read_context.
> +/// Create a dwarf_reader::reader.
>   ///
>   /// @param elf_path the path to the elf file the context is to be used for.
>   ///
> @@ -16839,14 +15788,14 @@ build_ir_node_from_die(read_context&	ctxt,
>   /// file.
>   ///
>   /// @param environment the environment used by the current context.
> -/// This environment contains resources needed by the reader and by
> +/// This environment contains resources needed by the DWARF reader and by
>   /// the types and declarations that are to be created later.  Note
>   /// that ABI artifacts that are to be compared all need to be created
>   /// within the same environment.
>   ///
>   /// Please also note that the life time of this environment object
>   /// must be greater than the life time of the resulting @ref
> -/// read_context the context uses resources that are allocated in the
> +/// reader the context uses resources that are allocated in the
>   /// environment.
>   ///
>   /// @param load_all_types if set to false only the types that are
> @@ -16858,33 +15807,27 @@ build_ir_node_from_die(read_context&	ctxt,
>   /// linux kernel symbol tables when determining if a symbol is
>   /// exported or not.
>   ///
> -/// @return a smart pointer to the resulting dwarf_reader::read_context.
> -read_context_sptr
> -create_read_context(const std::string&		elf_path,
> +/// @return a smart pointer to the resulting dwarf_reader::reader.
> +elf_based_reader_sptr
> +create_dwarf_reader(const std::string&		elf_path,
>   		    const vector<char**>&	debug_info_root_paths,
> -		    ir::environment*		environment,
> +		    environment&		environment,
>   		    bool			load_all_types,
>   		    bool			linux_kernel_mode)
>   {
> -  // Create a DWARF Front End Library handle to be used by functions
> -  // of that library.
> -  read_context_sptr result(new read_context(elf_path, debug_info_root_paths,
> -					    environment, load_all_types,
> -					    linux_kernel_mode));
> -  return result;
> -}
>   
> -/// Getter for the path to the binary this @ref read_context is for.
> -///
> -/// @return the path to the binary the @ref read_context is for.
> -const string&
> -read_context_get_path(const read_context& ctxt)
> -{return ctxt.elf_path();}
> +  reader_sptr r = reader::create(elf_path,
> +				 debug_info_root_paths,
> +				 environment,
> +				 load_all_types,
> +				 linux_kernel_mode);
> +  return static_pointer_cast<elf_based_reader>(r);
> +}
>   
> -/// Re-initialize a read_context so that it can re-used to read
> +/// Re-initialize a reader so that it can re-used to read
>   /// another binary.
>   ///
> -/// @param ctxt the context to re-initialize.
> +/// @param rdr the context to re-initialize.
>   ///
>   /// @param elf_path the path to the elf file the context is to be used
>   /// for.
> @@ -16895,14 +15838,14 @@ read_context_get_path(const read_context& ctxt)
>   /// file.
>   ///
>   /// @param environment the environment used by the current context.
> -/// This environment contains resources needed by the reader and by
> +/// This environment contains resources needed by the DWARF reader and by
>   /// the types and declarations that are to be created later.  Note
>   /// that ABI artifacts that are to be compared all need to be created
>   /// within the same environment.
>   ///
>   /// Please also note that the life time of this environment object
>   /// must be greater than the life time of the resulting @ref
> -/// read_context the context uses resources that are allocated in the
> +/// reader the context uses resources that are allocated in the
>   /// environment.
>   ///
>   /// @param load_all_types if set to false only the types that are
> @@ -16914,137 +15857,17 @@ read_context_get_path(const read_context& ctxt)
>   /// linux kernel symbol tables when determining if a symbol is
>   /// exported or not.
>   ///
> -/// @return a smart pointer to the resulting dwarf_reader::read_context.
> -void
> -reset_read_context(read_context_sptr	&ctxt,
> -		   const std::string&	 elf_path,
> -		   const vector<char**>& debug_info_root_path,
> -		   ir::environment*	 environment,
> -		   bool		 read_all_types,
> -		   bool		 linux_kernel_mode)
> -{
> -  if (ctxt)
> -    ctxt->initialize(elf_path, debug_info_root_path, environment,
> -		     read_all_types, linux_kernel_mode);
> -}
> -
> -/// Add suppressions specifications to the set of suppressions to be
> -/// used during the construction of the ABI internal representation
> -/// (the ABI corpus) from ELF and DWARF.
> -///
> -/// During the construction of the ABI corpus, ABI artifacts that
> -/// match the a given suppression specification are dropped on the
> -/// floor; that is, they are discarded and won't be part of the final
> -/// ABI corpus.  This is a way to reduce the amount of data held by
> -/// the final ABI corpus.
> -///
> -/// Note that the suppression specifications provided to this function
> -/// are only considered during the construction of the ABI corpus.
> -/// For instance, they are not taken into account during e.g
> -/// comparisons of two ABI corpora that might happen later.  If you
> -/// want to apply suppression specificatins to the comparison (or
> -/// reporting) of ABI corpora please refer to the documentation of the
> -/// @ref diff_context type to learn how to set suppressions that are
> -/// to be used in that context.
> -///
> -/// @param ctxt the context that is going to be used by functions that
> -/// read ELF and DWARF information to construct and ABI corpus.
> -///
> -/// @param supprs the suppression specifications to be applied during
> -/// the construction of the ABI corpus.
> -void
> -add_read_context_suppressions(read_context& ctxt,
> -			      const suppr::suppressions_type& supprs)
> -{
> -  for (suppr::suppressions_type::const_iterator i = supprs.begin();
> -       i != supprs.end();
> -       ++i)
> -    if ((*i)->get_drops_artifact_from_ir())
> -      ctxt.get_suppressions().push_back(*i);
> -}
> -
> -/// Set the @ref corpus_group being created to the current read context.
> -///
> -/// @param ctxt the read_context to consider.
> -///
> -/// @param group the @ref corpus_group to set.
> +/// @return a smart pointer to the resulting dwarf_reader::reader.
>   void
> -set_read_context_corpus_group(read_context& ctxt,
> -			      corpus_group_sptr& group)
> -{
> -  ctxt.cur_corpus_group_ = group;
> -}
> -
> -/// Read all @ref abigail::translation_unit possible from the debug info
> -/// accessible from an elf file, stuff them into a libabigail ABI
> -/// Corpus and return it.
> -///
> -/// @param ctxt the context to use for reading the elf file.
> -///
> -/// @param resulting_corp a pointer to the resulting abigail::corpus.
> -///
> -/// @return the resulting status.
> -corpus_sptr
> -read_corpus_from_elf(read_context& ctxt, status& status)
> -{
> -  status = STATUS_UNKNOWN;
> -
> -  // Load debug info from the elf path.
> -  if (!ctxt.load_debug_info())
> -    status |= STATUS_DEBUG_INFO_NOT_FOUND;
> -
> -  {
> -    string alt_di_path;
> -    if (refers_to_alt_debug_info(ctxt, alt_di_path) && !ctxt.alt_dwarf())
> -      status |= STATUS_ALT_DEBUG_INFO_NOT_FOUND;
> -  }
> -
> -  ctxt.load_elf_properties();  // DT_SONAME, DT_NEEDED, architecture
> -
> -  if (!ctxt.symtab() || !ctxt.symtab()->has_symbols())
> -    status |= STATUS_NO_SYMBOLS_FOUND;
> -
> -  if (// If no elf symbol was found ...
> -      status & STATUS_NO_SYMBOLS_FOUND
> -      // ... or if debug info was found but not the required alternate
> -      // debug info ...
> -      || ((status & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
> -	  && !(status & STATUS_DEBUG_INFO_NOT_FOUND)))
> -    // ... then we cannot handle the binary.
> -    return corpus_sptr();
> -
> -  // Read the variable and function descriptions from the debug info
> -  // we have, through the dwfl handle.
> -  corpus_sptr corp = read_debug_info_into_corpus(ctxt);
> -
> -  status |= STATUS_OK;
> -
> -  return corp;
> -}
> -
> -/// Read a corpus and add it to a given @ref corpus_group.
> -///
> -/// @param ctxt the reading context to consider.
> -///
> -/// @param group the @ref corpus_group to add the new corpus to.
> -///
> -/// @param status output parameter. The status of the read.  It is set
> -/// by this function upon its completion.
> -corpus_sptr
> -read_and_add_corpus_to_group_from_elf(read_context& ctxt,
> -				      corpus_group& group,
> -				      status& status)
> +reset_dwarf_reader(elf_based_reader&	rdr,
> +		   const std::string&	elf_path,
> +		   const vector<char**>&debug_info_root_path,
> +		   bool		read_all_types,
> +		   bool		linux_kernel_mode)
>   {
> -  corpus_sptr result;
> -  corpus_sptr corp = read_corpus_from_elf(ctxt, status);
> -  if (status & STATUS_OK)
> -    {
> -      if (!corp->get_group())
> -	group.add_corpus(corp);
> -      result = corp;
> -    }
> -
> -  return result;
> +  reader& r = dynamic_cast<reader&>(rdr);
> +  r.initialize(elf_path, debug_info_root_path,
> +	       read_all_types, linux_kernel_mode);
>   }
>   
>   /// Read all @ref abigail::translation_unit possible from the debug info
> @@ -17063,7 +15886,7 @@ read_and_add_corpus_to_group_from_elf(read_context& ctxt,
>   /// containing the debug info file.
>   ///
>   /// @param environment the environment used by the current context.
> -/// This environment contains resources needed by the reader and by
> +/// This environment contains resources needed by the DWARF reader and by
>   /// the types and declarations that are to be created later.  Note
>   /// that ABI artifacts that are to be compared all need to be created
>   /// within the same environment.  Also, the lifetime of the
> @@ -17082,16 +15905,16 @@ read_and_add_corpus_to_group_from_elf(read_context& ctxt,
>   corpus_sptr
>   read_corpus_from_elf(const std::string& elf_path,
>   		     const vector<char**>& debug_info_root_paths,
> -		     ir::environment*	environment,
> +		     environment&	environment,
>   		     bool		load_all_types,
> -		     status&		status)
> +		     fe_iface::status&	status)
>   {
> -  read_context_sptr c = create_read_context(elf_path,
> -					    debug_info_root_paths,
> -					    environment,
> -					    load_all_types);
> -  read_context& ctxt = *c;
> -  return read_corpus_from_elf(ctxt, status);
> +  elf_based_reader_sptr rdr =
> +    dwarf_reader::reader::create(elf_path, debug_info_root_paths,
> +				 environment, load_all_types,
> +				 /*linux_kernel_mode=*/false);
> +
> +  return rdr->read_corpus(status);
>   }
>   
>   /// Look into the symbol tables of a given elf file and see if we find
> @@ -17111,7 +15934,7 @@ read_corpus_from_elf(const std::string& elf_path,
>   /// @return true iff the symbol was found among the publicly exported
>   /// symbols of the ELF file.
>   bool
> -lookup_symbol_from_elf(const environment*		env,
> +lookup_symbol_from_elf(environment&			env,
>   		       const string&			elf_path,
>   		       const string&			symbol_name,
>   		       bool				demangle,
> @@ -17156,7 +15979,7 @@ lookup_symbol_from_elf(const environment*		env,
>   /// @return true iff a function with symbol name @p symbol_name is
>   /// found.
>   bool
> -lookup_public_function_symbol_from_elf(const environment*		env,
> +lookup_public_function_symbol_from_elf(environment&			env,
>   				       const string&			path,
>   				       const string&			symname,
>   				       vector<elf_symbol_sptr>&	syms)
> @@ -17183,218 +16006,6 @@ lookup_public_function_symbol_from_elf(const environment*		env,
>     return value;
>   }
>   
> -/// Check if the underlying elf file refers to an alternate debug info
> -/// file associated to it.
> -///
> -/// Note that "alternate debug info sections" is a GNU extension as
> -/// of DWARF4 and is described at
> -/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
> -///
> -/// @param ctxt the context used to read the elf file.
> -///
> -/// @param alt_di the path to the alternate debug info file.  This is
> -/// set iff the function returns true.
> -///
> -/// @return true if the ELF file refers to an alternate debug info
> -/// file.
> -bool
> -refers_to_alt_debug_info(const read_context&	ctxt,
> -			 string&		alt_di_path)
> -{
> -  if (!ctxt.alt_debug_info_path().empty())
> -    {
> -      alt_di_path = ctxt.alt_debug_info_path();
> -      return true;
> -    }
> -  return false;
> -}
> -
> -/// Check if the underlying elf file has an alternate debug info file
> -/// associated to it.
> -///
> -/// Note that "alternate debug info sections" is a GNU extension as
> -/// of DWARF4 and is described at
> -/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
> -///
> -/// @param ctxt the read_context to use to handle the underlying elf file.
> -///
> -/// @param has_alt_di out parameter.  This is set to true upon
> -/// succesful completion of the function iff an alternate debug info
> -/// file was found, false otherwise.  Note thas this parameter is set
> -/// only if the function returns STATUS_OK.
> -///
> -/// @param alt_debug_info_path if the function returned STATUS_OK and
> -/// if @p has been set to true, then this parameter contains the path
> -/// to the alternate debug info file found.
> -///
> -/// return STATUS_OK upon successful completion, false otherwise.
> -status
> -has_alt_debug_info(read_context&	ctxt,
> -		   bool&		has_alt_di,
> -		   string&		alt_debug_info_path)
> -{
> -  // Load debug info from the elf path.
> -  if (!ctxt.load_debug_info())
> -    return STATUS_DEBUG_INFO_NOT_FOUND;
> -
> -  if (ctxt.alt_dwarf())
> -    {
> -      has_alt_di = true;
> -      alt_debug_info_path = ctxt.alt_debug_info_path();
> -    }
> -  else
> -    has_alt_di = false;
> -
> -  return STATUS_OK;
> -}
> -
> -/// Check if a given elf file has an alternate debug info file
> -/// associated to it.
> -///
> -/// Note that "alternate debug info sections" is a GNU extension as
> -/// of DWARF4 and is described at
> -/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
> -///
> -/// @param elf_path the path to the elf file to consider.
> -///
> -/// @param a pointer to the root directory under which the split debug info
> -/// file associated to elf_path is to be found.  This has to be NULL
> -/// if the debug info file is not in a split file.
> -///
> -/// @param has_alt_di out parameter.  This is set to true upon
> -/// succesful completion of the function iff an alternate debug info
> -/// file was found, false otherwise.  Note thas this parameter is set
> -/// only if the function returns STATUS_OK.
> -///
> -/// @param alt_debug_info_path if the function returned STATUS_OK and
> -/// if @p has been set to true, then this parameter contains the path
> -/// to the alternate debug info file found.
> -///
> -/// return STATUS_OK upon successful completion, false otherwise.
> -status
> -has_alt_debug_info(const string&	elf_path,
> -		   char**		debug_info_root_path,
> -		   bool&		has_alt_di,
> -		   string&		alt_debug_info_path)
> -{
> -  vector<char**> di_roots;
> -  di_roots.push_back(debug_info_root_path);
> -  read_context_sptr c = create_read_context(elf_path, di_roots, 0);
> -  read_context& ctxt = *c;
> -
> -  // Load debug info from the elf path.
> -  if (!ctxt.load_debug_info())
> -    return STATUS_DEBUG_INFO_NOT_FOUND;
> -
> -  if (ctxt.alt_dwarf())
> -    {
> -      has_alt_di = true;
> -      alt_debug_info_path = ctxt.alt_debug_info_path();
> -    }
> -  else
> -    has_alt_di = false;
> -
> -  return STATUS_OK;
> -}
> -
> -/// Fetch the SONAME ELF property from an ELF binary file.
> -///
> -/// @param path The path to the elf file to consider.
> -///
> -/// @param soname out parameter. Set to the SONAME property of the
> -/// binary file, if it present in the ELF file.
> -///
> -/// return false if an error occured while looking for the SONAME
> -/// property in the binary, true otherwise.
> -bool
> -get_soname_of_elf_file(const string& path, string &soname)
> -{
> -
> -  int fd = open(path.c_str(), O_RDONLY);
> -  if (fd == -1)
> -    return false;
> -
> -  elf_version (EV_CURRENT);
> -  Elf* elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
> -
> -  GElf_Ehdr ehdr_mem;
> -  GElf_Ehdr* ehdr = gelf_getehdr (elf, &ehdr_mem);
> -  if (ehdr == NULL)
> -    return false;
> -
> -  for (int i = 0; i < ehdr->e_phnum; ++i)
> -    {
> -      GElf_Phdr phdr_mem;
> -      GElf_Phdr* phdr = gelf_getphdr (elf, i, &phdr_mem);
> -
> -      if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
> -        {
> -          Elf_Scn* scn = gelf_offscn (elf, phdr->p_offset);
> -          GElf_Shdr shdr_mem;
> -          GElf_Shdr* shdr = gelf_getshdr (scn, &shdr_mem);
> -          size_t entsize = (shdr != NULL && shdr->sh_entsize != 0
> -                            ? shdr->sh_entsize
> -                            : gelf_fsize (elf, ELF_T_DYN, 1, EV_CURRENT));
> -          int maxcnt = (shdr != NULL
> -                        ? shdr->sh_size / entsize : INT_MAX);
> -          ABG_ASSERT (shdr == NULL || (shdr->sh_type == SHT_DYNAMIC
> -				       || shdr->sh_type == SHT_PROGBITS));
> -          Elf_Data* data = elf_getdata (scn, NULL);
> -          if (data == NULL)
> -            break;
> -
> -          for (int cnt = 0; cnt < maxcnt; ++cnt)
> -            {
> -              GElf_Dyn dynmem;
> -              GElf_Dyn* dyn = gelf_getdyn (data, cnt, &dynmem);
> -              if (dyn == NULL)
> -                continue;
> -
> -              if (dyn->d_tag == DT_NULL)
> -                break;
> -
> -              if (dyn->d_tag != DT_SONAME)
> -                continue;
> -
> -              soname = elf_strptr (elf, shdr->sh_link, dyn->d_un.d_val);
> -              break;
> -            }
> -          break;
> -        }
> -    }
> -
> -  elf_end(elf);
> -  close(fd);
> -
> -  return true;
> -}
> -
> -/// Get the type of a given elf type.
> -///
> -/// @param path the absolute path to the ELF file to analyzed.
> -///
> -/// @param type the kind of the ELF file designated by @p path.
> -///
> -/// @param out parameter.  Is set to the type of ELF file of @p path.
> -/// This parameter is set iff the function returns true.
> -///
> -/// @return true iff the file could be opened and analyzed.
> -bool
> -get_type_of_elf_file(const string& path, elf_type& type)
> -{
> -  int fd = open(path.c_str(), O_RDONLY);
> -  if (fd == -1)
> -    return false;
> -
> -  elf_version (EV_CURRENT);
> -  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
> -  type = elf_file_type(elf);
> -  elf_end(elf);
> -  close(fd);
> -
> -  return true;
> -}
> -
>   }// end namespace dwarf_reader
>   
>   }// end namespace abigail
> diff --git a/src/abg-elf-based-reader.cc b/src/abg-elf-based-reader.cc
> new file mode 100644
> index 00000000..b8e5eb09
> --- /dev/null
> +++ b/src/abg-elf-based-reader.cc
> @@ -0,0 +1,102 @@
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +// -*- Mode: C++ -*-
> +//
> +// Copyright (C) 2022 Red Hat, Inc.
> +//
> +// Author: Dodji Seketeli
> +
> +/// @file
> +///
> +/// This file contains the definitions of the entry points of the
> +/// generic interface for ELF-based front-ends.  The generic interface
> +/// for ELF-based front-ends is named @ref elf_based_reader.  Examples
> +/// of front-ends that implement that interface are @ref
> +/// abigail::dwarf_reader::reader and abigail::ctf_raeder::reader.
> +
> +#include "abg-internal.h"
> +
> +// <headers defining libabigail's API go under here>
> +ABG_BEGIN_EXPORT_DECLARATIONS
> +
> +#include "abg-elf-based-reader.h"
> +
> +ABG_END_EXPORT_DECLARATIONS
> +// </headers defining libabigail's API>
> +namespace abigail
> +{
> +
> +/// The private data of the @ref elf_based_reader type.
> +struct elf_based_reader::priv
> +{
> +
> +  void
> +  initialize()
> +  {
> +  }
> +
> +  priv()
> +  {
> +    initialize();
> +  }
> +}; // end struct elf_based_reader::priv
> +
> +/// Constructor of the @erf elf_based_reader type.
> +///
> +/// @param elf_path the path the ELF file to read.
> +///
> +/// @param debug_info_root_paths a vector of paths to look into for
> +/// split debug info files.
> +///
> +/// @param env the environment used by the reader.
> +elf_based_reader::elf_based_reader(const std::string& elf_path,
> +				   const vector<char**>& debug_info_root_paths,
> +				   environment& env)
> +  : elf_reader::reader(elf_path, debug_info_root_paths, env),
> +    priv_(new priv)
> +{
> +  priv_->initialize();
> +}
> +
> +/// Destructor of the reader.
> +elf_based_reader::~elf_based_reader()
> +{delete priv_;}
> +
> +/// Reset (re-initialize) the resources used by the current reader.
> +///
> +/// This frees the resources of the current reader and gets it ready
> +/// to read data from another ELF file.
> +///
> +/// @param elf_path the path to the new ELF file to consider.
> +///
> +/// @param debug_info_root_paths a vector of paths to look into for
> +/// split debug info files.
> +void
> +elf_based_reader::reset(const std::string& elf_path,
> +			const vector<char**>& debug_info_root_paths)
> +{
> +  elf_reader::reader::reset(elf_path, debug_info_root_paths);
> +  priv_->initialize();
> +}
> +
> +/// Read an ABI corpus and add it to a given corpus group.
> +///
> +/// @param group the corpus group to consider.  The new corpus is
> +/// added to this group.
> +///
> +/// @param status output parameter.  This is the status of the
> +/// creation of the current ABI corpus.  It's set by this function iff
> +/// a non-nil @ref corpus_sptr is returned.
> +///
> +/// @return the resulting ABI corpus.
> +ir::corpus_sptr
> +elf_based_reader::read_and_add_corpus_to_group(ir::corpus_group& group,
> +					       fe_iface::status& status)
> +{
> +  ir::corpus_sptr corp = read_corpus(status);
> +
> +  if (status & fe_iface::STATUS_OK)
> +    group.add_corpus(corp);
> +  return corp;
> +}
> +
> +} // end namespace abigail
> diff --git a/src/abg-elf-helpers.cc b/src/abg-elf-helpers.cc
> index cbcf5428..8221ff84 100644
> --- a/src/abg-elf-helpers.cc
> +++ b/src/abg-elf-helpers.cc
> @@ -6,11 +6,13 @@
>   /// @file
>   ///
>   /// This contains the definitions of the ELF utilities for the dwarf reader.
> -
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <limits.h>
> +#include <elfutils/libdwfl.h>
>   #include "abg-elf-helpers.h"
> -
> -#include <elf.h>
> -
>   #include "abg-tools-utils.h"
>   
>   namespace abigail
> @@ -1333,6 +1335,179 @@ address_is_in_opd_section(Elf* elf_handle, Dwarf_Addr addr)
>     return false;
>   }
>   
> +/// Get data tag information of an ELF file by looking up into its
> +/// dynamic segment
> +///
> +/// @param elf the elf handle to use for the query.
> +///
> +/// @param dt_tag data tag to look for in dynamic segment
> +/// @param dt_tag_data vector of found information for a given @p data_tag
> +///
> +/// @return true iff data tag @p data_tag was found
> +bool
> +lookup_data_tag_from_dynamic_segment(Elf*                       elf,
> +                                     Elf64_Sxword               data_tag,
> +                                     vector<string>&            dt_tag_data)
> +{
> +  size_t num_prog_headers = 0;
> +  bool found = false;
> +  if (elf_getphdrnum(elf, &num_prog_headers) < 0)
> +    return found;
> +
> +  // Cycle through each program header.
> +  for (size_t i = 0; i < num_prog_headers; ++i)
> +    {
> +      GElf_Phdr phdr_mem;
> +      GElf_Phdr *phdr = gelf_getphdr(elf, i, &phdr_mem);
> +      if (phdr == NULL || phdr->p_type != PT_DYNAMIC)
> +        continue;
> +
> +      // Poke at the dynamic segment like a section, so that we can
> +      // get its section header information; also we'd like to read
> +      // the data of the segment by using elf_getdata() but that
> +      // function needs a Elf_Scn data structure to act on.
> +      // Elfutils doesn't really have any particular function to
> +      // access segment data, other than the functions used to
> +      // access section data.
> +      Elf_Scn *dynamic_section = gelf_offscn(elf, phdr->p_offset);
> +      GElf_Shdr  shdr_mem;
> +      GElf_Shdr *dynamic_section_header = gelf_getshdr(dynamic_section,
> +						       &shdr_mem);
> +      if (dynamic_section_header == NULL
> +          || dynamic_section_header->sh_type != SHT_DYNAMIC)
> +        continue;
> +
> +      // Get data of the dynamic segment (seen as a section).
> +      Elf_Data *data = elf_getdata(dynamic_section, NULL);
> +      if (data == NULL)
> +        continue;
> +
> +      // Get the index of the section headers string table.
> +      size_t string_table_index = 0;
> +      ABG_ASSERT (elf_getshdrstrndx(elf, &string_table_index) >= 0);
> +
> +      size_t dynamic_section_header_entry_size = gelf_fsize(elf,
> +                                                            ELF_T_DYN, 1,
> +                                                            EV_CURRENT);
> +
> +      GElf_Shdr link_mem;
> +      GElf_Shdr *link =
> +        gelf_getshdr(elf_getscn(elf,
> +                                dynamic_section_header->sh_link),
> +		     &link_mem);
> +      ABG_ASSERT(link != NULL);
> +
> +      size_t num_dynamic_section_entries =
> +        dynamic_section_header->sh_size / dynamic_section_header_entry_size;
> +
> +      // Now walk through all the DT_* data tags that are in the
> +      // segment/section
> +      for (size_t j = 0; j < num_dynamic_section_entries; ++j)
> +        {
> +          GElf_Dyn dynamic_section_mem;
> +          GElf_Dyn *dynamic_section = gelf_getdyn(data,
> +                                                  j,
> +                                                  &dynamic_section_mem);
> +          if (dynamic_section->d_tag == data_tag)
> +            {
> +              dt_tag_data.push_back(elf_strptr(elf,
> +                                               dynamic_section_header->sh_link,
> +					       dynamic_section->d_un.d_val));
> +              found = true;
> +            }
> +        }
> +    }
> +  return found;
> +}
> +
> +const Dwfl_Callbacks&
> +initialize_dwfl_callbacks(Dwfl_Callbacks& cb,
> +			  char** debug_info_root_path)
> +{
> +  cb.find_debuginfo = dwfl_standard_find_debuginfo;
> +  cb.section_address = dwfl_offline_section_address;
> +  cb.debuginfo_path = debug_info_root_path;
> +  return cb;
> +}
> +
> +dwfl_sptr
> +create_new_dwfl_handle(Dwfl_Callbacks& cb)
> +{
> +  dwfl_sptr handle(dwfl_begin(&cb), dwfl_deleter());
> +  return handle;
> +}
> +
> +/// Fetch the SONAME ELF property from an ELF binary file.
> +///
> +/// @param path The path to the elf file to consider.
> +///
> +/// @param soname out parameter. Set to the SONAME property of the
> +/// binary file, if it present in the ELF file.
> +///
> +/// return false if an error occured while looking for the SONAME
> +/// property in the binary, true otherwise.
> +bool
> +get_soname_of_elf_file(const string& path, string &soname)
> +{
> +
> +  int fd = open(path.c_str(), O_RDONLY);
> +  if (fd == -1)
> +    return false;
> +
> +  elf_version (EV_CURRENT);
> +  Elf* elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
> +
> +  GElf_Ehdr ehdr_mem;
> +  GElf_Ehdr* ehdr = gelf_getehdr (elf, &ehdr_mem);
> +  if (ehdr == NULL)
> +    return false;
> +
> +  for (int i = 0; i < ehdr->e_phnum; ++i)
> +    {
> +      GElf_Phdr phdr_mem;
> +      GElf_Phdr* phdr = gelf_getphdr (elf, i, &phdr_mem);
> +
> +      if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
> +        {
> +          Elf_Scn* scn = gelf_offscn (elf, phdr->p_offset);
> +          GElf_Shdr shdr_mem;
> +          GElf_Shdr* shdr = gelf_getshdr (scn, &shdr_mem);
> +          size_t entsize = (shdr != NULL && shdr->sh_entsize != 0
> +                            ? shdr->sh_entsize
> +                            : gelf_fsize (elf, ELF_T_DYN, 1, EV_CURRENT));
> +          int maxcnt = (shdr != NULL
> +                        ? shdr->sh_size / entsize : INT_MAX);
> +          ABG_ASSERT (shdr == NULL || (shdr->sh_type == SHT_DYNAMIC
> +				       || shdr->sh_type == SHT_PROGBITS));
> +          Elf_Data* data = elf_getdata (scn, NULL);
> +          if (data == NULL)
> +            break;
> +
> +          for (int cnt = 0; cnt < maxcnt; ++cnt)
> +            {
> +              GElf_Dyn dynmem;
> +              GElf_Dyn* dyn = gelf_getdyn (data, cnt, &dynmem);
> +              if (dyn == NULL)
> +                continue;
> +
> +              if (dyn->d_tag == DT_NULL)
> +                break;
> +
> +              if (dyn->d_tag != DT_SONAME)
> +                continue;
> +
> +              soname = elf_strptr (elf, shdr->sh_link, dyn->d_un.d_val);
> +              break;
> +            }
> +          break;
> +        }
> +    }
> +
> +  elf_end(elf);
> +  close(fd);
> +
> +  return true;
> +}
>   
>   } // end namespace elf_helpers
>   } // end namespace abigail
> diff --git a/src/abg-elf-helpers.h b/src/abg-elf-helpers.h
> index e884c6a3..b0b105de 100644
> --- a/src/abg-elf-helpers.h
> +++ b/src/abg-elf-helpers.h
> @@ -24,6 +24,27 @@ namespace abigail
>   namespace elf_helpers
>   {
>   
> +/// A functor used by @ref dwfl_sptr.
> +struct dwfl_deleter
> +{
> +  void
> +  operator()(Dwfl* dwfl)
> +  {dwfl_end(dwfl);}
> +};//end struct dwfl_deleter
> +
> +/// A convenience typedef for a shared pointer to a Dwfl.
> +typedef shared_ptr<Dwfl> dwfl_sptr;
> +
> +/// Convenience typedef for a map which key is an elf address and
> +/// which value is an elf_symbol_sptr.
> +typedef unordered_map<GElf_Addr, elf_symbol_sptr> addr_elf_symbol_sptr_map_type;
> +
> +/// Convenience typedef for a set of ELF addresses.
> +typedef unordered_set<GElf_Addr> address_set_type;
> +
> +/// Convenience typedef for a shared pointer to an @ref address_set_type.
> +typedef shared_ptr<address_set_type> address_set_sptr;
> +
>   //
>   // ELF Value Converters
>   //
> @@ -173,6 +194,16 @@ is_linux_kernel_module(Elf *elf_handle);
>   bool
>   is_linux_kernel(Elf *elf_handle);
>   
> +//
> +// elfutils helpers
> +//
> +
> +const Dwfl_Callbacks&
> +initialize_dwfl_callbacks(Dwfl_Callbacks&, char**);
> +
> +dwfl_sptr
> +create_new_dwfl_handle(Dwfl_Callbacks&);
> +
>   //
>   // Misc Helpers
>   //
> @@ -195,6 +226,13 @@ maybe_adjust_et_rel_sym_addr_to_abs_addr(Elf* elf_handle, GElf_Sym* sym);
>   bool
>   address_is_in_opd_section(Elf* elf_handle, Dwarf_Addr addr);
>   
> +bool
> +lookup_data_tag_from_dynamic_segment(Elf*                       elf,
> +                                     Elf64_Sxword               data_tag,
> +                                     vector<string>&            dt_tag_data);
> +
> +bool
> +get_soname_of_elf_file(const string& path, string &soname);
>   } // end namespace elf_helpers
>   } // end namespace abigail
>   
> diff --git a/src/abg-elf-reader-common.cc b/src/abg-elf-reader-common.cc
> deleted file mode 100644
> index 1d0aff15..00000000
> --- a/src/abg-elf-reader-common.cc
> +++ /dev/null
> @@ -1,90 +0,0 @@
> -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> -// -*- Mode: C++ -*-
> -//
> -// Copyright (C) 2013-2022 Oracle, Inc.
> -//
> -// Author: Jose E. Marchesi
> -
> -/// @file
> -///
> -/// This file contains the implementation of facilities to deal with
> -/// status codes related to ELF based readers.
> -///
> -/// More generally, this file contains definitions related to
> -/// facilities shared by the various readers that handle the ELF
> -/// format, e.g, the DWARF and CTF realder.
> -#include "config.h"
> -
> -#include "abg-internal.h"
> -
> -// <headers defining libabigail's API go under here>
> -ABG_BEGIN_EXPORT_DECLARATIONS
> -
> -#include "abg-elf-reader-common.h"
> -
> -ABG_END_EXPORT_DECLARATIONS
> -// </headers defining libabigail's API>
> -
> -namespace abigail
> -{
> -
> -namespace elf_reader
> -{
> -
> -status
> -operator|(status l, status r)
> -{
> -  return static_cast<status>(static_cast<unsigned>(l)
> -			     | static_cast<unsigned>(r));
> -}
> -
> -status
> -operator&(status l, status r)
> -{
> -  return static_cast<status>(static_cast<unsigned>(l)
> -			     & static_cast<unsigned>(r));
> -}
> -
> -status&
> -operator|=(status& l, status r)
> -{
> -  l = l | r;
> -  return l;
> -}
> -
> -status&
> -operator&=(status& l, status r)
> -{
> -  l = l & r;
> -  return l;
> -}
> -
> -/// Return a diagnostic status with english sentences to describe the
> -/// problems encoded in a given abigail::elf_reader::status, if
> -/// there is an error.
> -///
> -/// @param status the status to diagnose
> -///
> -/// @return a string containing sentences that describe the possible
> -/// errors encoded in @p s.  If there is no error to encode, then the
> -/// empty string is returned.
> -std::string
> -status_to_diagnostic_string(status s)
> -{
> -  std::string str;
> -
> -  if (s & STATUS_DEBUG_INFO_NOT_FOUND)
> -    str += "could not find debug info\n";
> -
> -  if (s & STATUS_ALT_DEBUG_INFO_NOT_FOUND)
> -    str += "could not find alternate debug info\n";
> -
> -  if (s & STATUS_NO_SYMBOLS_FOUND)
> -    str += "could not load ELF symbols\n";
> -
> -  return str;
> -}
> -
> -}// end namespace elf_reader
> -
> -}// end namespace abigail
> diff --git a/src/abg-elf-reader.cc b/src/abg-elf-reader.cc
> new file mode 100644
> index 00000000..346d17a2
> --- /dev/null
> +++ b/src/abg-elf-reader.cc
> @@ -0,0 +1,890 @@
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +// -*- Mode: C++ -*-
> +//
> +// Copyright (C) 2022 Red Hat, Inc.
> +//
> +// Author: Dodji Seketeli
> +
> +/// @file
> +///
> +/// Elf reader stuff
> +
> +#include "abg-internal.h"
> +
> +#include <fcntl.h> /* For open(3) */
> +#include <unistd.h>
> +#include <iostream>
> +#include <cstring>
> +#include <libgen.h>
> +#include <fcntl.h>
> +#include <elfutils/libdwfl.h>
> +
> +
> +#include "abg-symtab-reader.h"
> +#include "abg-suppression-priv.h"
> +#include "abg-elf-helpers.h"
> +
> +// <headers defining libabigail's API go under here>
> +ABG_BEGIN_EXPORT_DECLARATIONS
> +#include "abg-elf-reader.h"
> +#include "abg-tools-utils.h"
> +ABG_END_EXPORT_DECLARATIONS
> +// </headers defining libabigail's API>
> +namespace abigail
> +{
> +
> +using namespace elf_helpers;
> +
> +namespace elf_reader
> +{
> +
> +/// Find the file name of the alternate debug info file.
> +///
> +/// @param elf_module the elf module to consider.
> +///
> +/// @param out parameter.  Is set to the file name of the alternate
> +/// debug info file, iff this function returns true.
> +///
> +/// @return true iff the location of the alternate debug info file was
> +/// found.
> +static bool
> +find_alt_dwarf_debug_info_link(Dwfl_Module *elf_module,
> +			       string &alt_file_name)
> +{
> +  GElf_Addr bias = 0;
> +  Dwarf *dwarf = dwfl_module_getdwarf(elf_module, &bias);
> +  Elf *elf = dwarf_getelf(dwarf);
> +  GElf_Ehdr ehmem, *elf_header;
> +  elf_header = gelf_getehdr(elf, &ehmem);
> +
> +  Elf_Scn* section = 0;
> +  while ((section = elf_nextscn(elf, section)) != 0)
> +    {
> +      GElf_Shdr header_mem, *header;
> +      header = gelf_getshdr(section, &header_mem);
> +      if (header->sh_type != SHT_PROGBITS)
> +	continue;
> +
> +      const char *section_name = elf_strptr(elf,
> +					    elf_header->e_shstrndx,
> +					    header->sh_name);
> +
> +      char *alt_name = 0;
> +      char *buildid = 0;
> +      size_t buildid_len = 0;
> +      if (section_name != 0
> +	  && strcmp(section_name, ".gnu_debugaltlink") == 0)
> +	{
> +	  Elf_Data *data = elf_getdata(section, 0);
> +	  if (data != 0 && data->d_size != 0)
> +	    {
> +	      alt_name = (char*) data->d_buf;
> +	      char *end_of_alt_name =
> +		(char *) memchr(alt_name, '\0', data->d_size);
> +	      buildid_len = data->d_size - (end_of_alt_name - alt_name + 1);
> +	      if (buildid_len == 0)
> +		return false;
> +	      buildid = end_of_alt_name + 1;
> +	    }
> +	}
> +      else
> +	continue;
> +
> +      if (buildid == 0 || alt_name == 0)
> +	return false;
> +
> +      alt_file_name = alt_name;
> +      return true;
> +    }
> +
> +  return false;
> +}
> +
> +/// Find alternate debuginfo file of a given "link" under a set of
> +/// root directories.
> +///
> +/// The link is a string that is read by the function
> +/// find_alt_dwarf_debug_info_link().  That link is a path that is relative
> +/// to a given debug info file, e.g, "../../../.dwz/something.debug".
> +/// It designates the alternate debug info file associated to a given
> +/// debug info file.
> +///
> +/// This function will thus try to find the .dwz/something.debug file
> +/// under some given root directories.
> +///
> +/// @param root_dirs the set of root directories to look from.
> +///
> +/// @param alt_file_name a relative path to the alternate debug info
> +/// file to look for.
> +///
> +/// @param alt_file_path the resulting absolute path to the alternate
> +/// debuginfo path denoted by @p alt_file_name and found under one of
> +/// the directories in @p root_dirs.  This is set iff the function
> +/// returns true.
> +///
> +/// @return true iff the function found the alternate debuginfo file.
> +static bool
> +find_alt_dwarf_debug_info_path(const vector<char**> root_dirs,
> +			       const string &alt_file_name,
> +			       string &alt_file_path)
> +{
> +  if (alt_file_name.empty())
> +    return false;
> +
> +  string altfile_name = tools_utils::trim_leading_string(alt_file_name, "../");
> +
> +  for (vector<char**>::const_iterator i = root_dirs.begin();
> +       i != root_dirs.end();
> +       ++i)
> +    if (tools_utils::find_file_under_dir(**i, altfile_name, alt_file_path))
> +      return true;
> +
> +  return false;
> +}
> +
> +/// Return the alternate debug info associated to a given main debug
> +/// info file.
> +///
> +/// @param elf_module the elf module to consider.
> +///
> +/// @param debug_root_dirs a set of root debuginfo directories under
> +/// which too look for the alternate debuginfo file.
> +///
> +/// @param alt_file_name output parameter.  This is set to the file
> +/// path of the alternate debug info file associated to @p elf_module.
> +/// This is set iff the function returns a non-null result.
> +///
> +/// @param alt_fd the file descriptor used to access the alternate
> +/// debug info.  If this parameter is set by the function, then the
> +/// caller needs to fclose it, otherwise the file descriptor is going
> +/// to be leaked.  Note however that on recent versions of elfutils
> +/// where libdw.h contains the function dwarf_getalt(), this parameter
> +/// is set to 0, so it doesn't need to be fclosed.
> +///
> +/// Note that the alternate debug info file is a DWARF extension as of
> +/// DWARF 4 ans is decribed at
> +/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
> +///
> +/// @return the alternate debuginfo, or null.  If @p alt_fd is
> +/// non-zero, then the caller of this function needs to call
> +/// dwarf_end() on the returned alternate debuginfo pointer,
> +/// otherwise, it's going to be leaked.
> +static Dwarf*
> +find_alt_dwarf_debug_info(Dwfl_Module *elf_module,
> +			  const vector<char**> debug_root_dirs,
> +			  string& alt_file_name,
> +			  int& alt_fd)
> +{
> +  if (elf_module == 0)
> +    return 0;
> +
> +  Dwarf* result = 0;
> +  find_alt_dwarf_debug_info_link(elf_module, alt_file_name);
> +
> +#ifdef LIBDW_HAS_DWARF_GETALT
> +  // We are on recent versions of elfutils where the function
> +  // dwarf_getalt exists, so let's use it.
> +  Dwarf_Addr bias = 0;
> +  Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
> +  result = dwarf_getalt(dwarf);
> +  alt_fd = 0;
> +#else
> +  // We are on an old version of elfutils where the function
> +  // dwarf_getalt doesn't exist yet, so let's open code its
> +  // functionality
> +  char *alt_name = 0;
> +  const char *file_name = 0;
> +  void **user_data = 0;
> +  Dwarf_Addr low_addr = 0;
> +  char *alt_file = 0;
> +
> +  file_name = dwfl_module_info(elf_module, &user_data,
> +			       &low_addr, 0, 0, 0, 0, 0);
> +
> +  alt_fd = dwfl_standard_find_debuginfo(elf_module, user_data,
> +					file_name, low_addr,
> +					alt_name, file_name,
> +					0, &alt_file);
> +
> +  result = dwarf_begin(alt_fd, DWARF_C_READ);
> +#endif
> +
> +  if (result == 0)
> +    {
> +      // So we didn't find the alternate debuginfo file from the
> +      // information that is in the debuginfo file associated to
> +      // elf_module.  Maybe the alternate debuginfo file is located
> +      // under one of the directories in debug_root_dirs.  So let's
> +      // look in there.
> +      string alt_file_path;
> +      if (!find_alt_dwarf_debug_info_path(debug_root_dirs,
> +					  alt_file_name,
> +					  alt_file_path))
> +	return result;
> +
> +      // If we reach this point it means we have found the path to the
> +      // alternate debuginfo file and it's in alt_file_path.  So let's
> +      // open it and read it.
> +      int fd = open(alt_file_path.c_str(), O_RDONLY);
> +      if (fd == -1)
> +	return result;
> +      result = dwarf_begin(fd, DWARF_C_READ);
> +
> +#ifdef LIBDW_HAS_DWARF_GETALT
> +      Dwarf_Addr bias = 0;
> +      Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
> +      dwarf_setalt(dwarf, result);
> +#endif
> +    }
> +
> +  return result;
> +}
> +
> +/// Private data of the @ref elf_reader::reader type.
> +struct reader::priv
> +{
> +  reader&				rdr;
> +  Elf*					elf_handle		= nullptr;
> +  Elf_Scn*				symtab_section		= nullptr;
> +  string				elf_architecture;
> +  vector<string>			dt_needed;
> +  // An abstraction of the symbol table.  This is loaded lazily, on
> +  // demand.
> +  mutable symtab_reader::symtab_sptr	symt;
> +  // Where split debug info is to be searched for on disk.
> +  vector<char**>			debug_info_root_paths;
> +  // Some very useful callback functions that elfutils needs to
> +  // perform various tasks.
> +  Dwfl_Callbacks			offline_callbacks;
> +  // A pointer to the DWARF Front End Library handle of elfutils.
> +  // This is useful to perform all kind of things at a higher level.
> +  dwfl_sptr				dwfl_handle;
> +  // The address range of the offline elf file we are looking at.
> +  Dwfl_Module*				elf_module		= nullptr;
> +  // A pointer to the DWARF debug info, if found by locate_dwarf_debug_info.
> +  Dwarf*				dwarf_handle		= nullptr;
> +  // A pointer to the ALT DWARF debug info, which is the debug info
> +  // that is constructed by the DWZ tool.  It's made of all the type
> +  // information that was redundant in the DWARF.  DWZ put it there
> +  // and make the DWARF reference it in here.
> +  Dwarf*				alt_dwarf_handle	= nullptr;
> +  string				alt_dwarf_path;
> +  int					alt_dwarf_fd		= 0;
> +  Elf_Scn*				ctf_section		= nullptr;
> +  Elf_Scn*				alt_ctf_section	= nullptr;
> +
> +  priv(reader& reeder, const std::string& elf_path,
> +       const vector<char**>& debug_info_roots)
> +    : rdr(reeder)
> +  {
> +    rdr.corpus_path(elf_path);
> +    initialize(debug_info_roots);
> +  }
> +
> +  /// Reset the private data of @elf elf_reader::reader.
> +  ///
> +  /// @param debug_info_roots the vector of new directories where to
> +  /// look for split debug info file.
> +  void
> +  initialize(const vector<char**>& debug_info_roots)
> +  {
> +    debug_info_root_paths = debug_info_roots;
> +    symt.reset();
> +    dwfl_handle.reset();
> +    elf_module = nullptr;
> +    elf_handle = nullptr;
> +  }
> +
> +  /// Setup the necessary plumbing to open the ELF file and find all
> +  /// the associated split debug info files.
> +  ///
> +  /// This function also setup the various handles on the opened ELF
> +  /// file and whatnot.
> +  void
> +  crack_open_elf_file()
> +  {
> +    // Initialize the callback functions used by elfutils.
> +    elf_helpers::initialize_dwfl_callbacks(offline_callbacks,
> +					   debug_info_root_paths.empty()
> +					   ? nullptr
> +					   : debug_info_root_paths.front());
> +
> +    // Create a handle to the DWARF Front End Library that we'll need.
> +    dwfl_handle = elf_helpers::create_new_dwfl_handle(offline_callbacks);
> +
> +    const string& elf_path = rdr.corpus_path();
> +    // Get the set of addresses that make up the ELF file we are
> +    // looking at.
> +    elf_module =
> +      dwfl_report_offline(dwfl_handle.get(),
> +			  basename(const_cast<char*>(elf_path.c_str())),
> +			  elf_path.c_str(), -1);
> +    dwfl_report_end(dwfl_handle.get(), 0, 0);
> +    ABG_ASSERT(elf_module);
> +
> +    // Finally, get and handle at the representation of the ELF file
> +    // we've just cracked open.
> +    GElf_Addr bias = 0;
> +    elf_handle = dwfl_module_getelf(elf_module, &bias);
> +    ABG_ASSERT(elf_handle);
> +  }
> +
> +  /// Find the alternate debuginfo file associated to a given elf file.
> +  ///
> +  /// @param elf_module represents the elf file to consider.
> +  ///
> +  /// @param alt_file_name the resulting path to the alternate
> +  /// debuginfo file found.  This is set iff the function returns a
> +  /// non-nil value.
> +  Dwarf*
> +  find_alt_dwarf_debug_info(Dwfl_Module*	elf_module,
> +			    string&		alt_file_name,
> +			    int&		alt_fd)
> +  {
> +    Dwarf *result = 0;
> +    result = elf_reader::find_alt_dwarf_debug_info(elf_module,
> +						   debug_info_root_paths,
> +						   alt_file_name, alt_fd);
> +    return result;
> +  }
> +
> +  /// Locate the DWARF debug info in the ELF file.
> +  ///
> +  /// This also knows how to locate split debug info.
> +  void
> +  locate_dwarf_debug_info()
> +  {
> +    ABG_ASSERT(dwfl_handle);
> +
> +    if (dwarf_handle)
> +      return;
> +
> +    // First let's see if the ELF file that was cracked open does have
> +    // some DWARF debug info embedded.
> +    Dwarf_Addr bias = 0;
> +    dwarf_handle = dwfl_module_getdwarf(elf_module, &bias);
> +
> +    // If no debug info was found in the binary itself, then look for
> +    // split debuginfo files under multiple possible debuginfo roots.
> +    for (vector<char**>::const_iterator i = debug_info_root_paths.begin();
> +	 dwarf_handle == 0 && i != debug_info_root_paths.end();
> +	 ++i)
> +      {
> +	offline_callbacks.debuginfo_path = *i;
> +	dwarf_handle = dwfl_module_getdwarf(elf_module, &bias);
> +      }
> +
> +    alt_dwarf_handle = find_alt_dwarf_debug_info(elf_module,
> +						 alt_dwarf_path,
> +						 alt_dwarf_fd);
> +  }
> +
> +  /// Locate the CTF "alternate" debug information associated with the
> +  /// current ELF file ( and split out somewhere else).
> +  ///
> +  /// This is a sub-routine of @ref locate_ctf_debug_info().
> +  void
> +  locate_alt_ctf_debug_info()
> +  {
> +    Elf_Scn *section =
> +      elf_helpers::find_section(elf_handle,
> +				".gnu_debuglink",
> +				SHT_PROGBITS);
> +
> +    std::string name;
> +    Elf_Data *data;
> +    if (section
> +	&& (data = elf_getdata(section, nullptr))
> +	&& data->d_size != 0)
> +      name = (char *) data->d_buf;
> +
> +    if (!name.empty())
> +      for (const auto& path : rdr.debug_info_root_paths())
> +	{
> +	  std::string file_path;
> +	  if (!tools_utils::find_file_under_dir(*path, name, file_path))
> +	    continue;
> +
> +	  int fd;
> +	  if ((fd = open(file_path.c_str(), O_RDONLY)) == -1)
> +	    continue;
> +
> +	  Elf *hdl;
> +	  if ((hdl = elf_begin(fd, ELF_C_READ, nullptr)) == nullptr)
> +	    {
> +	      close(fd);
> +	      continue;
> +	    }
> +
> +	  // unlikely .ctf was designed to be present in stripped file
> +	  alt_ctf_section =
> +	    elf_helpers::find_section(hdl, ".ctf", SHT_PROGBITS);
> +          break;
> +
> +	  elf_end(hdl);
> +	  close(fd);
> +	}
> +  }
> +
> +  /// Locate the CTF debug information associated with the current ELF
> +  /// file.  It also locates the CTF debug information that is split
> +  /// out in a separate file.
> +  void
> +  locate_ctf_debug_info()
> +  {
> +    ABG_ASSERT(elf_handle);
> +
> +    ctf_section = elf_helpers::find_section_by_name(elf_handle, ".ctf");
> +    if (ctf_section == nullptr)
> +      {
> +	locate_alt_ctf_debug_info();
> +	ctf_section = alt_ctf_section;
> +      }
> +  }
> +}; //end reader::priv
> +
> +/// The constructor of the @ref elf_reader::reader type.
> +///
> +/// @param elf_path the path to the ELF file to read from.
> +///
> +/// @param debug_info_root a vector of directory paths to look into
> +/// for split debug information files.
> +///
> +/// @param env the environment which the reader operates in.
> +reader::reader(const string&		elf_path,
> +	       const vector<char**>&	debug_info_roots,
> +	       ir::environment&	env)
> +  : fe_iface(elf_path, env),
> +    priv_(new priv(*this, elf_path, debug_info_roots))
> +{
> +  priv_->crack_open_elf_file();
> +  priv_->locate_dwarf_debug_info();
> +}
> +
> +/// The destructor of the @ref elf_reader::reader type.
> +reader::~reader()
> +{delete priv_;}
> +
> +/// Resets (erase) the resources used by the current @ref
> +/// elf_reader::reader type.
> +///
> +/// This lets the reader in a state where it's ready to read from
> +/// another ELF file.
> +///
> +/// @param elf_path the new ELF path to read from.
> +///
> +/// @param debug_info_roots a vector of directory paths to look into
> +/// for split debug information files.
> +void
> +reader::reset(const std::string&	elf_path,
> +	      const vector<char**>&	debug_info_roots)
> +{
> +  corpus_path(elf_path);
> +  priv_->initialize(debug_info_roots);
> +  priv_->crack_open_elf_file();
> +  priv_->locate_dwarf_debug_info();
> +}
> +
> +/// Getter of the vector of directory paths to look into for split
> +/// debug information files.
> +///
> +/// @return the vector of directory paths to look into for split
> +/// debug information files.
> +const vector<char**>&
> +reader::debug_info_root_paths() const
> +{return priv_->debug_info_root_paths;}
> +
> +/// Getter of the functions used by the DWARF Front End library of
> +/// elfutils to locate DWARF debug information.
> +///
> +/// @return the functions used by the DWARF Front End library of
> +const Dwfl_Callbacks&
> +reader::dwfl_offline_callbacks() const
> +{return priv_->offline_callbacks;}
> +
> +/// Getter of the functions used by the DWARF Front End library of
> +/// elfutils to locate DWARF debug information.
> +///
> +/// @return the functions used by the DWARF Front End library of
> +Dwfl_Callbacks&
> +reader::dwfl_offline_callbacks()
> +{return priv_->offline_callbacks;}
> +
> +/// Getter of the handle used to access ELF information from the
> +/// current ELF file.
> +///
> +/// @return the handle used to access ELF information from the current
> +/// ELF file.
> +Elf*
> +reader::elf_handle() const
> +{return priv_->elf_handle;}
> +
> +/// Getter of the handle used to access DWARF information from the
> +/// current ELF file.
> +///
> +/// @return the handle used to access DWARF information from the
> +/// current ELF file.
> +const Dwarf*
> +reader::dwarf_debug_info() const
> +{return priv_->dwarf_handle;}
> +
> +/// Getter of the handle use to access DWARF information from the
> +/// alternate split DWARF information.
> +///
> +/// In other words, this accesses the factorized DWARF information
> +/// that has been constructed by the DWZ tool to de-duplicate DWARF
> +/// information on disk.
> +///
> +/// @return the handle use to access DWARF information from the
> +/// alternate split DWARF information.
> +const Dwarf*
> +reader::alternate_dwarf_debug_info() const
> +{return priv_->alt_dwarf_handle;}
> +
> +
> +/// Getter of the path to the alternate split DWARF information file,
> +/// on disk.  In othe words, this returns the path to the factorized
> +/// DWARF information used by the current ELF file, created by the
> +/// 'DWZ' tool.
> +///
> +/// @return the path to the alternate split DWARF information file,
> +/// on disk.
> +const string&
> +reader::alternate_dwarf_debug_info_path() const
> +{return priv_->alt_dwarf_path;}
> +
> +/// Check if the underlying elf file refers to an alternate debug info
> +/// file associated to it.
> +///
> +/// Note that "alternate debug info sections" is a GNU extension as
> +/// of DWARF4 and is described at
> +/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
> +///
> +/// @param alt_di the path to the alternate debug info file.  This is
> +/// set iff the function returns true.
> +///
> +/// @return true if the ELF file refers to an alternate debug info
> +/// file.
> +bool
> +reader::refers_to_alt_debug_info(string& alt_di_path) const
> +{
> +  if (!alternate_dwarf_debug_info_path().empty())
> +    {
> +      alt_di_path = alternate_dwarf_debug_info_path();
> +      return true;
> +    }
> +  return false;
> +}
> +
> +/// Find and return a pointer to the ELF symbol table
> +/// section.
> +///
> +/// @return a pointer to the ELF symbol table section.
> +const Elf_Scn*
> +reader::find_symbol_table_section() const
> +{
> +  if (!priv_->symtab_section)
> +      priv_->symtab_section =
> +	elf_helpers::find_symbol_table_section(elf_handle());
> +    return priv_->symtab_section;
> +}
> +
> +/// Clear the pointer to the ELF symbol table section.
> +void
> +reader::reset_symbol_table_section()
> +{priv_->symtab_section = nullptr;}
> +
> +/// Find and return a pointer to the the CTF section.
> +///
> +/// @return a pointer to the the CTF section.
> +const Elf_Scn*
> +reader::find_ctf_section() const
> +{
> +  if (priv_->ctf_section == nullptr)
> +    priv_->locate_ctf_debug_info();
> +
> +  if (priv_->ctf_section)
> +    return priv_->ctf_section;
> +
> +  return priv_->alt_ctf_section;
> +}
> +
> +/// Find and return a pointer to the alternate CTF section of the
> +/// current ELF file.
> +///
> +/// @return a pointer to the alternate CTF section of the current ELF
> +/// file.
> +const Elf_Scn*
> +reader::find_alternate_ctf_section() const
> +{
> +  if (priv_->alt_ctf_section == nullptr)
> +    priv_->locate_alt_ctf_debug_info();
> +
> +  return priv_->alt_ctf_section;
> +}
> +
> +/// Get the value of the DT_NEEDED property of the current ELF file.
> +///
> +/// @return the value of the DT_NEEDED property.
> +const vector<string>&
> +reader::dt_needed()const
> +{return priv_->dt_needed;}
> +
> +
> +/// Get the value of the 'ARCHITECTURE' property of the current ELF file.
> +///
> +/// @return the value of the 'ARCHITECTURE' property of the current
> +/// ELF file.
> +const string&
> +reader::elf_architecture() const
> +{return priv_->elf_architecture;}
> +
> +/// Getter of an abstract representation of the symbol table of the
> +/// underlying ELF file.
> +///
> +/// Note that the symbol table is loaded lazily, upon the first
> +/// invocation of this member function.
> +///
> +/// @returnt the symbol table.
> +symtab_reader::symtab_sptr&
> +reader::symtab() const
> +{
> +  ABG_ASSERT(elf_handle());
> +
> +  if (!priv_->symt)
> +    priv_->symt = symtab_reader::symtab::load
> +      (elf_handle(), options().env,
> +       [&](const elf_symbol_sptr& symbol)
> +       {return suppr::is_elf_symbol_suppressed(*this, symbol);});
> +
> +  if (!priv_->symt)
> +    std::cerr << "Symbol table of '" << corpus_path()
> +	      << "' could not be loaded\n";
> +  return priv_->symt;
> +}
> +
> +/// Test if a given function symbol has been exported.
> +///
> +/// @param symbol_address the address of the symbol we are looking
> +/// for.  Note that this address must be a relative offset from the
> +/// beginning of the .text section, just like the kind of addresses
> +/// that are present in the .symtab section.
> +///
> +/// @returnthe elf symbol if found, or nil otherwise.
> +elf_symbol_sptr
> +reader::function_symbol_is_exported(GElf_Addr symbol_address) const
> +{
> +  elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
> +  if (!symbol)
> +    return symbol;
> +
> +  if (!symbol->is_function() || !symbol->is_public())
> +    return elf_symbol_sptr();
> +
> +  address_set_sptr set;
> +  bool looking_at_linux_kernel_binary =
> +    load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
> +
> +  if (looking_at_linux_kernel_binary)
> +    {
> +	if (symbol->is_in_ksymtab())
> +	  return symbol;
> +	return elf_symbol_sptr();
> +    }
> +
> +  return symbol;
> +}
> +
> +/// Test if a given variable symbol has been exported.
> +///
> +/// @param symbol_address the address of the symbol we are looking
> +/// for.  Note that this address must be a relative offset from the
> +/// beginning of the .text section, just like the kind of addresses
> +/// that are present in the .symtab section.
> +///
> +/// @returnthe elf symbol if found, or nil otherwise.
> +elf_symbol_sptr
> +reader::variable_symbol_is_exported(GElf_Addr symbol_address) const
> +{
> +  elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
> +  if (!symbol)
> +    return symbol;
> +
> +  if (!symbol->is_variable() || !symbol->is_public())
> +    return elf_symbol_sptr();
> +
> +  address_set_sptr set;
> +  bool looking_at_linux_kernel_binary =
> +    load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
> +
> +  if (looking_at_linux_kernel_binary)
> +    {
> +	if (symbol->is_in_ksymtab())
> +	  return symbol;
> +	return elf_symbol_sptr();
> +    }
> +
> +  return symbol;
> +}
> +
> +/// Load the DT_NEEDED and DT_SONAME elf TAGS.
> +void
> +reader::load_dt_soname_and_needed()
> +{
> +  elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
> +						    DT_NEEDED,
> +						    priv_->dt_needed);
> +
> +  vector<string> dt_tag_data;
> +  elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
> +						    DT_SONAME,
> +						    dt_tag_data);
> +  if (!dt_tag_data.empty())
> +    dt_soname(dt_tag_data[0]);
> +}
> +
> +/// Read the string representing the architecture of the current ELF
> +/// file.
> +void
> +reader::load_elf_architecture()
> +{
> +  if (!elf_handle())
> +    return;
> +
> +  GElf_Ehdr eh_mem;
> +  GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
> +
> +  priv_->elf_architecture =
> +    elf_helpers::e_machine_to_string(elf_header->e_machine);
> +}
> +
> +/// Load various ELF data.
> +///
> +/// This function loads ELF data that are not symbol maps or debug
> +/// info.  That is, things like various tags, elf architecture and
> +/// so on.
> +void
> +reader::load_elf_properties()
> +{
> +  // Note that we don't load the symbol table as it's loaded lazily,
> +  // on demand.
> +
> +  load_dt_soname_and_needed();
> +  load_elf_architecture();
> +}
> +
> +/// Read the ELF information associated to the current ELF file and
> +/// construct an ABI representation from it.
> +///
> +/// Note that this reader doesn't know how to interpret any debug
> +/// information so the resulting ABI corpus won't have any type
> +/// information.  Rather, it will only have ELF symbol representation.
> +///
> +/// To have type information, consider using readers that know how to
> +/// interpret the symbolic type information comprised in DWARF, CTF or
> +/// other symbolic debug information format, like the @ref or
> +/// abigail::dwarf_reader::reader, @ref abigail::ctf_reader::reader
> +/// readers.
> +///
> +/// @return the resulting ABI corpus.
> +ir::corpus_sptr
> +reader::read_corpus(status& status)
> +{
> +  status = STATUS_UNKNOWN;
> +
> +  load_elf_properties(); // DT_SONAME, DT_NEEDED, architecture
> +  corpus()->set_soname(dt_soname());
> +  corpus()->set_needed(dt_needed());
> +  corpus()->set_architecture_name(elf_architecture());
> +
> +  // See if we could find symbol tables.
> +  if (!symtab() || !symtab()->has_symbols())
> +    {
> +      status |= STATUS_NO_SYMBOLS_FOUND;
> +      // We found no ELF symbol, so we can't handle the binary.
> +      return corpus_sptr();
> +    }
> +
> +  // Set symbols information to the corpus.
> +  corpus()->set_symtab(symtab());
> +
> +  // If we couldn't load debug info from the elf path, then say it.
> +    if (dwarf_debug_info() == nullptr
> +	&& find_ctf_section() == nullptr)
> +      status |= STATUS_DEBUG_INFO_NOT_FOUND;
> +
> +    status |= STATUS_OK;
> +
> +    return corpus();
> +}
> +
> +/// Get the SONAME property of a designated ELF file.
> +///
> +/// @param path the path to the ELF file to consider.
> +///
> +/// @param soname output parameter.  This is set to the SONAME of the
> +/// file located at @p path, iff this function return true.
> +///
> +/// @return true iff the SONAME property was found in the ELF file
> +/// located at @p path and set into the argument of the parameter @p
> +/// soname.
> +bool
> +get_soname_of_elf_file(const string& path, string &soname)
> +{return elf_helpers::get_soname_of_elf_file(path, soname);}
> +
> +/// Convert the type of ELF file into @ref elf_type.
> +///
> +/// @param elf the elf handle to use for the query.
> +///
> +/// @return the @ref elf_type for a given elf type.
> +static elf_reader::elf_type
> +elf_file_type(Elf* elf)
> +{
> +  GElf_Ehdr ehdr_mem;
> +  GElf_Ehdr *header = gelf_getehdr (elf, &ehdr_mem);
> +  vector<string> dt_debug_data;
> +
> +  switch (header->e_type)
> +    {
> +    case ET_DYN:
> +      if (lookup_data_tag_from_dynamic_segment(elf, DT_DEBUG, dt_debug_data))
> +	return elf_reader::ELF_TYPE_PI_EXEC;
> +      else
> +	return elf_reader::ELF_TYPE_DSO;
> +    case ET_EXEC:
> +      return elf_reader::ELF_TYPE_EXEC;
> +    case ET_REL:
> +      return elf_reader::ELF_TYPE_RELOCATABLE;
> +    default:
> +      return elf_reader::ELF_TYPE_UNKNOWN;
> +    }
> +}
> +
> +/// Get the type of a given elf type.
> +///
> +/// @param path the absolute path to the ELF file to analyzed.
> +///
> +/// @param type the kind of the ELF file designated by @p path.
> +///
> +/// @param out parameter.  Is set to the type of ELF file of @p path.
> +/// This parameter is set iff the function returns true.
> +///
> +/// @return true iff the file could be opened and analyzed.
> +bool
> +get_type_of_elf_file(const string& path, elf_reader::elf_type& type)
> +{
> +  int fd = open(path.c_str(), O_RDONLY);
> +  if (fd == -1)
> +    return false;
> +
> +  elf_version (EV_CURRENT);
> +  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
> +  type = elf_file_type(elf);
> +  elf_end(elf);
> +  close(fd);
> +
> +  return true;
> +}
> +
> +}// end namespace elf_reader
> +} // end namespace abigail
> diff --git a/src/abg-fe-iface.cc b/src/abg-fe-iface.cc
> new file mode 100644
> index 00000000..88993248
> --- /dev/null
> +++ b/src/abg-fe-iface.cc
> @@ -0,0 +1,411 @@
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +// -*- Mode: C++ -*-
> +//
> +// Copyright (C) 2022 Red Hat, Inc.
> +//
> +// Author: Dodji Seketeli
> +
> +/// @file
> +///
> +/// This file contains the definitions of the the fe_iface base type.
> +
> +#include "abg-internal.h"
> +// <headers defining libabigail's API go under here>
> +ABG_BEGIN_EXPORT_DECLARATIONS
> +
> +#include "abg-corpus.h"
> +#include "abg-fe-iface.h"
> +
> +ABG_END_EXPORT_DECLARATIONS
> +// </headers defining libabigail's API>
> +
> +namespace abigail
> +{
> +
> +/// The private data structure for the @ref fe_iface type.
> +struct fe_iface::priv
> +{
> +  std::string corpus_path;
> +  std::string dt_soname;
> +  fe_iface::options_type options;
> +  suppr::suppressions_type suppressions;
> +  ir::corpus_sptr corpus;
> +  ir::corpus_group_sptr corpus_group;
> +
> +  priv(const std::string& path, environment& e)
> +    : corpus_path(path), options(e)
> +  {
> +    initialize();
> +  }
> +
> +  /// This function resets the data of @ref fe_iface::priv data so
> +  /// that it can be re-used again.
> +  void
> +  initialize()
> +  {
> +    //TODO: initialize the options.
> +    corpus_path.clear();
> +    dt_soname.clear();
> +    suppressions.clear();
> +    corpus_group.reset();
> +  }
> +}; //end struct fe_iface::priv
> +
> +/// Constructor of the type @ref fe_iface::options_type.
> +///
> +/// @param e the environment used by the Front End Interface.
> +fe_iface::options_type::options_type(environment& e)
> +  : env(e)
> +{
> +}
> +
> +/// Constructor of the type @ref fe_iface.
> +///
> +/// @param corpus_path the path to the file represented by the ABI
> +/// corpus that is going to be built by this Front End.
> +///
> +/// @param e the environment in which the Front End operates.
> +fe_iface::fe_iface(const std::string& corpus_path, environment& e)
> +  : priv_(new priv(corpus_path, e))
> +{
> +}
> +
> +/// Desctructor of the Front End Interface.
> +fe_iface::~fe_iface()
> +{delete priv_;}
> +
> +/// Re-initialize the current Front End.
> +///
> +/// @param corpus_path the path to the file for which a new corpus is
> +/// to be created.
> +///
> +/// @param e the environment in which the Front End operates.
> +void
> +fe_iface::reset(const std::string& corpus_path,
> +		environment& e)
> +{
> +  delete priv_;
> +  priv_ = new fe_iface::priv(corpus_path, e);
> +}
> +
> +/// Getter of the the options of the current Front End Interface.
> +///
> +/// @return the options of the current Front End Interface.
> +const fe_iface::options_type&
> +fe_iface::options() const
> +{return priv_->options;}
> +
> +/// Getter of the the options of the current Front End Interface.
> +///
> +/// @return the options of the current Front End Interface.
> +fe_iface::options_type&
> +fe_iface::options()
> +{return priv_->options;}
> +
> +/// Getter of the path to the file which an ABI corpus is to be
> +/// created for.
> +///
> +/// @return the path to the file which an ABI corpus is to be created
> +/// for.
> +const std::string&
> +fe_iface::corpus_path() const
> +{return priv_->corpus_path;}
> +
> +/// Setter of the path to the file which an ABI corpus is to be
> +/// created for.
> +///
> +/// @param p the new path to the file which an ABI corpus is to be
> +/// created for.
> +void
> +fe_iface::corpus_path(const std::string& p)
> +{priv_->corpus_path = p;}
> +
> +/// Getter for the SONAME of the analyzed binary.
> +///
> +/// @return the SONAME of the analyzed binary.
> +const string&
> +fe_iface::dt_soname() const
> +{return priv_->dt_soname;}
> +
> +/// Getter for the SONAME of the analyzed binary.
> +///
> +/// @return the SONAME of the analyzed binary.
> +void
> +fe_iface::dt_soname(const string& soname)
> +{priv_->dt_soname = soname;}
> +
> +/// Test if the input binary is to be considered as a Linux Kernel
> +/// binary.
> +///
> +/// @return true iff the input binary is to be considered as a Linux
> +/// Kernel binary.
> +bool
> +fe_iface::load_in_linux_kernel_mode() const
> +{return priv_->options.load_in_linux_kernel_mode;}
> +
> +/// Getter of the vector of suppression specifications associated with
> +/// the current front-end.
> +///
> +/// @return the vector of suppression specifications associated with
> +/// the current front-end.
> +suppr::suppressions_type&
> +fe_iface::suppressions()
> +{return priv_->suppressions;}
> +
> +/// Getter of the vector of suppression specifications associated with
> +/// the current front-end.
> +///
> +/// @return the vector of suppression specifications associated with
> +/// the current front-end.
> +const suppr::suppressions_type&
> +fe_iface::suppressions() const
> +{return priv_->suppressions;}
> +
> +/// Setter of the vector of suppression specifications associated with
> +/// the current front-end.
> +///
> +/// @param supprs the new vector of suppression specifications
> +/// associated with the current front-end.
> +void
> +fe_iface::suppressions(suppr::suppressions_type& supprs)
> +{priv_->suppressions = supprs;}
> +
> +/// Add suppressions specifications to the set of suppressions to be
> +/// used during the construction of the ABI internal representation
> +/// (the ABI corpus) from the input file.
> +///
> +/// During the construction of the ABI corpus, ABI artifacts that
> +/// match a given suppression specification are dropped on the floor;
> +/// that is, they are discarded and won't be part of the final ABI
> +/// corpus.  This is a way to reduce the amount of data held by the
> +/// final ABI corpus.
> +///
> +/// Note that the suppression specifications provided to this function
> +/// are only considered during the construction of the ABI corpus.
> +/// For instance, they are not taken into account during e.g
> +/// comparisons of two ABI corpora that might happen later.  If you
> +/// want to apply suppression specificatins to the comparison (or
> +/// reporting) of ABI corpora please refer to the documentation of the
> +/// @ref diff_context type to learn how to set suppressions that are
> +/// to be used in that context.
> +///
> +/// @param supprs the suppression specifications to be applied during
> +/// the construction of the ABI corpus.
> +void
> +fe_iface::add_suppressions(const suppr::suppressions_type& supprs)
> +{
> +  for (const auto& s : supprs)
> +    if (s->get_drops_artifact_from_ir())
> +      suppressions().push_back(s);
> +}
> +
> +/// Getter for the ABI corpus being built by the current front-end.
> +///
> +/// @return the ABI corpus being built by the current front-end.
> +corpus_sptr
> +fe_iface::corpus()
> +{
> +  if (!priv_->corpus)
> +    {
> +      priv_->corpus = std::make_shared<ir::corpus>(options().env,
> +						   corpus_path());
> +    }
> +  return priv_->corpus;
> +}
> +
> +/// Getter for the ABI corpus being built by the current front-end.
> +///
> +/// @return the ABI corpus being built by the current front-end.
> +const corpus_sptr
> +fe_iface::corpus() const
> +{return const_cast<fe_iface*>(this)->corpus();}
> +
> +/// Getter for the ABI corpus group being built by the current front-end.
> +///
> +/// @return the ABI corpus group being built by the current front-end.
> +corpus_group_sptr&
> +fe_iface::corpus_group()
> +{return priv_->corpus_group;}
> +
> +/// Getter for the ABI corpus group being built by the current front-end.
> +///
> +/// @return the ABI corpus group being built by the current front-end.
> +const corpus_group_sptr&
> +fe_iface::corpus_group() const
> +{return const_cast<fe_iface*>(this)->corpus_group();}
> +
> +/// Setter for the ABI corpus group being built by the current
> +/// front-end.
> +///
> +/// @param cg the new ABI corpus group being built by the current
> +/// front-end.
> +void
> +fe_iface::corpus_group(const ir::corpus_group_sptr& cg)
> +{priv_->corpus_group = cg;}
> +
> +/// Test if there is a corpus group being built.
> +///
> +/// @return if there is a corpus group being built, false otherwise.
> +bool
> +fe_iface::has_corpus_group() const
> +{return bool(corpus_group());}
> +
> +/// Return the main corpus from the current corpus group, if any.
> +///
> +/// @return the main corpus of the current corpus group, if any, nil
> +/// if no corpus group is being constructed.
> +corpus_sptr
> +fe_iface::main_corpus_from_current_group()
> +{
> +  if (corpus_group())
> +    return corpus_group()->get_main_corpus();
> +  return corpus_sptr();
> +}
> +
> +/// Test if the current corpus being built is the main corpus of the
> +/// current corpus group.
> +///
> +/// @return return true iff the current corpus being built is the
> +/// main corpus of the current corpus group.
> +bool
> +fe_iface::current_corpus_is_main_corpus_from_current_group()
> +{
> +  corpus_sptr main_corpus = main_corpus_from_current_group();
> +
> +  if (main_corpus.get() == corpus().get())
> +    return true;
> +
> +  return false;
> +}
> +
> +/// Return true if the current corpus is part of a corpus group
> +/// being built and if it's not the main corpus of the group.
> +///
> +/// For instance, this would