Files
third_party_libabigail/src/abg-corpus.cc
T
Matthias Maennich 58488c5f31 Replace individual license references with SPDX Identifiers
This patch replaces license headers with SPDX identifiers in all files
containing license headers.  For each file, the SPDX identifier
formally represents its current license.  Note that the list of SPDX
identifiers is available on the SPDX web site at
https://spdx.org/licenses.

For autoconf-archive/ax_prog_python_version.m4 however, there is a
little catch.  Dodji Seketeli wrote this ax_check_python_modules.m4.
Just like the other autoconf-archive macros, it makes sense to have it
under the FSF All Permissive license.  Actually, the terms of that
license was already in the file but then the license header was
wrongly set to GPLv2 with autoconf exception.  So I fixed that in this
commit by setting the SPDX identifier to FSFAP.

	* abigail.m4: Replace the license header with the SPDX identifier
	GPL-3.0-or-later WITH GCC-exception-3.1
	* autoconf-archive/ax_check_python_modules.m4: Correctly set the
	SPDX identifier to FSFAP.
	* autoconf-archive/ax_compare_version.m4: Replace the license
	header with the SPDX identifier FSFAP.
	* autoconf-archive/ax_prog_python_version.m4: Likewise.
	header with the SPDX identifier FSFAP.
	* autoconf-archive/ax_valgrind_check.m4: Likewise.
	* gen-changelog.py: Replace the license header with the SPDX
	identifier LGPL-2.0-or-later.
	* include/abg-comp-filter.h: Replace the license header with the
	SPDX identifier LGPL-3.0-or-later.
	* include/abg-comparison.h: Likewise.
	* include/abg-config.h: Likewise.
	* include/abg-corpus.h: Likewise.
	* include/abg-cxx-compat.h: Replace the license header with the
	SPDX identifier LGPL-2.0-or-later.
	* include/abg-diff-utils.h: Replace the license header with the
	SPDX identifier LGPL-3.0-or-later
	* include/abg-dwarf-reader.h: Likewise.
	* include/abg-fwd.h: Likewise.
	* include/abg-hash.h: Likewise.
	* include/abg-ini.h: Likewise.
	* include/abg-interned-str.h: Likewise.
	* include/abg-ir.h: Likewise.
	* include/abg-libxml-utils.h: Likewise.
	* include/abg-libzip-utils.h: Likewise.
	* include/abg-reader.h: Likewise.
	* include/abg-regex.h: Likewise.
	* include/abg-reporter.h: Likewise.
	* include/abg-sptr-utils.h: Likewise.
	* include/abg-suppression.h: Likewise.
	* include/abg-tools-utils.h: Likewise.
	* include/abg-traverse.h: Likewise.
	* include/abg-viz-common.h: Likewise.
	* include/abg-viz-dot.h: Likewise.
	* include/abg-viz-svg.h: Likewise.
	* include/abg-workers.h: Likewise.
	* include/abg-writer.h: Likewise.
	* install-sh: Replace the license header with the SPDX identifier MIT.
	* ltmain.sh: Replace the license header with the SPDX identifier
	GPL-2.0-or-later.  Note that this file has the libtool special
	exception which allows us to redistribute it under the general
	license of the project.
	* src/abg-comp-filter.cc: Replace the license header with the SPDX
	* src/abg-comparison-priv.h: Likewise.
	* src/abg-comparison.cc: Likewise.
	* src/abg-config.cc: Likewise.
	* src/abg-corpus-priv.h: Likewise.
	* src/abg-corpus.cc: Likewise.
	* src/abg-default-reporter.cc: Likewise.
	* src/abg-diff-utils.cc: Likewise.
	* src/abg-dwarf-reader.cc: Likewise.
	* src/abg-elf-helpers.cc: Likewise.
	* src/abg-elf-helpers.h: Likewise.
	* src/abg-regex.cc: Likewise.
	* src/abg-hash.cc: Likewise.
	* src/abg-ini.cc: Likewise.
	* src/abg-internal.h: Likewise.
	* src/abg-ir-priv.h: Likewise.
	* src/abg-ir.cc: Likewise.
	* src/abg-leaf-reporter.cc: Likewise.
	* src/abg-libxml-utils.cc: Likewise.
	* src/abg-libzip-utils.cc: Likewise.
	* src/abg-reader.cc: Likewise.
	* src/abg-reporter-priv.cc: Likewise.
	* src/abg-reporter-priv.h: Likewise.
	* src/abg-sptr-utils.cc: Likewise.
	* src/abg-suppression-priv.h: Likewise.
	* src/abg-suppression.cc: Likewise.
	* src/abg-tools-utils.cc: Likewise.
	* src/abg-traverse.cc: Likewise.
	* src/abg-viz-common.cc: Likewise.
	* src/abg-viz-dot.cc: Likewise.
	* src/abg-viz-svg.cc: Likewise.
	* src/abg-workers.cc: Likewise.
	* src/abg-writer.cc: Likewise.
	* tests/lib/catch.cc: Likewise.
	* tests/lib/catch.hpp: Add an SPDX identifier BSL-1.0.
	* tests/mockfedabipkgdiff.in: Replace the license header with the
	SPDX identifier GPL-3.0-or-later.
	* tests/print-diff-tree.cc: Likewise.
	* tests/runtestfedabipkgdiff.py.in: Replaace the license header
	with the SPDW identifier GPL-3.0-or-later.
	* tests/test-abicompat.cc: Replace the license header with the
	SPDX identifier LGPL-3.0-or-later.
	* tests/test-abidiff-exit.cc: Likewise.
	* tests/test-abidiff.cc: Likewise.
	* tests/test-alt-dwarf-file.cc: Likewise.
	* tests/test-annotate.cc: Likewise.
	* tests/test-cxx-compat.cc: Likewise.
	* tests/test-core-diff.cc: Likewise.
	* tests/test-diff-dwarf-abixml.cc: Likewise.
	* tests/test-diff-dwarf.cc: Likewise.
	* tests/test-diff-filter.cc: Likewise.
	* tests/test-diff-pkg.cc: Likewise.
	* tests/test-diff-suppr.cc: Likewise.
	* tests/test-diff2.cc: Likewise.
	* tests/test-dot.cc: Replace the license header with the
	SPDX identifier GPL-3.0-with-GCC-exception.
	* tests/test-elf-helpers.cc: Replace the license header with the
	SPDX identifier LGPL-3.0-or-later.
	* tests/test-ini.cc: Likewise.
	* tests/test-ir-walker.cc: Likewise.
	* tests/test-kmi-whitelist.cc: Likewise.
	* tests/test-lookup-syms.cc: Likewise.
	* tests/test-read-dwarf.cc: Likewise.
	* tests/test-read-write.cc: Likewise.
	* tests/test-svg.cc: Replace the license header with the SPDX
	identifier GPL-3.0-with-GCC-exception.
	* tests/test-symtab.cc: Replace the license header with the SPDX
	identifier LGPL-3.0-or-later.
	* tests/test-tools-utils.cc: Likewise.
	* tests/test-types-stability.cc: Likewise.
	* tests/test-utils.cc: Likewise.
	* tests/test-utils.h: Likewise.
	* tests/test-write-read-archive.cc: Likewise.
	* tools/abiar.cc: Likewise.
	* tools/abicompat.cc: Likewise.
	* tools/abidiff.cc: Likewise.
	* tools/abidw.cc: Likewise.
	* tools/abilint.cc: Likewise.
	* tools/abipkgdiff.cc: Likewise.
	* tools/abisym.cc: Likewise.
	* tools/binilint.cc: Likewise.
	* tools/fedabipkgdiff: Replace the license header with the
	SPDX identifier GPL-3.0-or-later.
	* tools/kmidiff.cc: Likewise.

Signed-off-by: Benjamin De Kosnik <bkoz@gnu.org>
Signed-off-by: Ben Woodard <woodard@redhat.com>
Signed-off-by: Chenxiong Qi <cqi@redhat.com>
Signed-off-by: Dodji Seketeli <dodji@redhat.com>
Signed-off-by: Giuliano Procida <gprocida@google.com>
Signed-off-by: Jan Engelhardt <jengelh@inai.de>
Signed-off-by: Jessica Yu <jeyu@kernel.org>
Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Mark Wielaard <mark@klomp.org>
Signed-off-by: Matthias Klose <doko@ubuntu.com>
Signed-off-by: Matthias Maennich <maennich@google.com>
Signed-off-by: Ondrej Oprala <ondrej.oprala@gmail.com>
Signed-off-by: Roland McGrath <roland@hack.frob.com>
Signed-off-by: Sinny Kumari <ksinny@gmail.com>
Signed-off-by: Slava Barinov <v.barinov@samsung.com>
2020-12-02 11:44:13 +01:00

2005 lines
61 KiB
C++

// SPDX-License-Identifier: LGPL-3.0-or-later
// -*- mode: C++ -*-
//
// Copyright (C) 2013-2020 Red Hat, Inc.
/// @file
#include "config.h"
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <stdexcept>
#include "abg-cxx-compat.h"
#include "abg-internal.h"
// <headers defining libabigail's API go under here>
ABG_BEGIN_EXPORT_DECLARATIONS
#include "abg-corpus.h"
#include "abg-ir.h"
#include "abg-reader.h"
#include "abg-sptr-utils.h"
#include "abg-tools-utils.h"
#include "abg-writer.h"
#if WITH_ZIP_ARCHIVE
#include "abg-libzip-utils.h"
#endif
ABG_END_EXPORT_DECLARATIONS
// </headers defining libabigail's API>
#include "abg-corpus-priv.h"
#include "abg-ir-priv.h"
namespace abigail
{
namespace ir
{
using std::ostringstream;
using abg_compat::unordered_map;
using std::list;
using std::vector;
#if WITH_ZIP_ARCHIVE
using zip_utils::zip_sptr;
using zip_utils::zip_file_sptr;
using zip_utils::open_archive;
using zip_utils::open_file_in_archive;
#endif // WITH_ZIP_ARCHIVE
using regex::regex_t_sptr;
/// Constructor of @ref corpus::exported_decls_builder.
///
/// @param fns a reference to the vector of exported functions.
///
/// @param vars a reference to the vector of exported variables.
///
/// @param fns_suppress_regexps the regular expressions that designate
/// the functions to suppress from the exported functions set.
///
/// @param vars_suppress_regexps the regular expressions that designate
/// the variables to suppress from the exported variables set.
///
/// @param fns_keep_regexps the regular expressions that designate the
/// functions to keep in the exported functions set.
///
/// @param fns_keep_regexps the regular expressions that designate the
/// functions to keep in the exported functions set.
///
/// @param vars_keep_regexps the regular expressions that designate
/// the variables to keep in the exported variables set.
///
/// @param sym_id_of_fns_to_keep the IDs of the functions to keep in
/// the exported functions set.
///
/// @param sym_id_of_vars_to_keep the IDs of the variables to keep in
/// the exported variables set.
corpus::exported_decls_builder
::exported_decls_builder(functions& fns,
variables& vars,
strings_type& fns_suppress_regexps,
strings_type& vars_suppress_regexps,
strings_type& fns_keep_regexps,
strings_type& vars_keep_regexps,
strings_type& sym_id_of_fns_to_keep,
strings_type& sym_id_of_vars_to_keep)
: priv_(new priv(fns, vars,
fns_suppress_regexps,
vars_suppress_regexps,
fns_keep_regexps,
vars_keep_regexps,
sym_id_of_fns_to_keep,
sym_id_of_vars_to_keep))
{
}
/// Getter for the reference to the vector of exported functions.
/// This vector is shared with with the @ref corpus. It's where the
/// set of exported function is ultimately stored.
///
/// @return a reference to the vector of exported functions.
const corpus::functions&
corpus::exported_decls_builder::exported_functions() const
{return priv_->fns_;}
/// Getter for the reference to the vector of exported functions.
/// This vector is shared with with the @ref corpus. It's where the
/// set of exported function is ultimately stored.
///
/// @return a reference to the vector of exported functions.
corpus::functions&
corpus::exported_decls_builder::exported_functions()
{return priv_->fns_;}
/// Getter for the reference to the vector of exported variables.
/// This vector is shared with with the @ref corpus. It's where the
/// set of exported variable is ultimately stored.
///
/// @return a reference to the vector of exported variables.
const corpus::variables&
corpus::exported_decls_builder::exported_variables() const
{return priv_->vars_;}
/// Getter for the reference to the vector of exported variables.
/// This vector is shared with with the @ref corpus. It's where the
/// set of exported variable is ultimately stored.
///
/// @return a reference to the vector of exported variables.
corpus::variables&
corpus::exported_decls_builder::exported_variables()
{return priv_->vars_;}
/// Consider at all the tunables that control wether a function should
/// be added to the set of exported function and if it fits in, add
/// the function to that set.
///
/// @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)
{
if (!fn->get_is_in_public_symbol_table())
return;
const string& fn_id = priv_->get_id(*fn);
ABG_ASSERT(!fn_id.empty());
if (priv_->fn_is_in_id_fns_map(fn))
return;
if (priv_->keep_wrt_id_of_fns_to_keep(fn)
&& priv_->keep_wrt_regex_of_fns_to_suppress(fn)
&& priv_->keep_wrt_regex_of_fns_to_keep(fn))
priv_->add_fn_to_exported(fn);
}
/// Consider at all the tunables that control wether a variable should
/// be added to the set of exported variable and if it fits in, add
/// the variable to that set.
///
/// @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)
{
if (!var->get_is_in_public_symbol_table())
return;
const string& var_id = priv_->get_id(*var);
ABG_ASSERT(!var_id.empty());
if (priv_->var_id_is_in_id_var_map(var_id))
return;
if (priv_->keep_wrt_id_of_vars_to_keep(var)
&& priv_->keep_wrt_regex_of_vars_to_suppress(var)
&& priv_->keep_wrt_regex_of_vars_to_keep(var))
priv_->add_var_to_exported(var);
}
// </corpus::exported_decls_builder>
/// Convenience typedef for a hash map of pointer to function_decl and
/// boolean.
typedef unordered_map<const function_decl*,
bool,
function_decl::hash,
function_decl::ptr_equal> fn_ptr_map_type;
/// Convenience typedef for a hash map of string and pointer to
/// function_decl.
typedef unordered_map<string, const function_decl*> str_fn_ptr_map_type;
/// Convenience typedef for a hash map of pointer to var_decl and boolean.
typedef unordered_map<const var_decl*,
bool,
var_decl::hash,
var_decl::ptr_equal> var_ptr_map_type;
/// This is a comparison functor for comparing pointers to @ref
/// function_decl.
struct func_comp
{
/// The comparisong operator for pointers to @ref function_decl. It
/// performs a string comparison of the mangled names of the
/// functions. If the functions don't have mangled names, it
/// compares their names instead.
///
/// @param first the first function to consider in the comparison.
///
/// @param second the second function to consider in the comparison.
///
/// @return true if the (mangled) name of the first function is less
/// than the (mangled)name of the second one, false otherwise.
bool
operator()(const function_decl* first,
const function_decl* second) const
{
ABG_ASSERT(first != 0 && second != 0);
string first_name, second_name;
first_name = first->get_linkage_name();
if (first_name.empty())
first_name = first->get_name();
ABG_ASSERT(!first_name.empty());
second_name = second->get_linkage_name();
if (second_name.empty())
second_name = second->get_name();
ABG_ASSERT(!second_name.empty());
return first_name < second_name;
}
};
/// This is a comparison functor for comparing pointers to @ref
/// var_decl.
struct var_comp
{
/// The comparison operator for pointers to @ref var_decl.
///
/// It perform a string comparison on the names of the variables.
///
/// @param first the first variable to consider for the comparison.
///
/// @param second the second variable to consider for the comparison.
///
/// @return true if first is less than second, false otherwise.
bool
operator()(const var_decl* first,
const var_decl* second) const
{
ABG_ASSERT(first != 0 && second != 0);
string first_name, second_name;
first_name = first->get_linkage_name();
if (first_name.empty())
{
first_name = first->get_pretty_representation();
second_name = second->get_pretty_representation();
ABG_ASSERT(!second_name.empty());
}
ABG_ASSERT(!first_name.empty());
if (second_name.empty())
second_name = second->get_linkage_name();
if (second_name.empty())
{
second_name = second->get_pretty_representation();
first_name = first->get_pretty_representation();
ABG_ASSERT(!first_name.empty());
}
ABG_ASSERT(!second_name.empty());
return first_name < second_name;
}
};
/// A comparison functor to compare elf_symbols for the purpose of
/// sorting.
struct comp_elf_symbols_functor
{
bool
operator()(const elf_symbol& l,
const elf_symbol& r) const
{return l.get_id_string() < r.get_id_string();}
bool
operator()(const elf_symbol_sptr l,
const elf_symbol_sptr r) const
{return operator()(*l, *r);}
}; // end struct comp_elf_symbols_functor
// <corpus stuff>
/// Build the tables of symbols that are not referenced by any
/// function or variables of corpus::get_functions() or
/// corpus::get_variables().
///
/// Note that this function considers the list of function and
/// variable symbols to keep, that is provided by
/// corpus::get_sym_ids_of_fns_to_keep() and
/// corpus::get_sym_ids_of_vars_to_keep(). If a given unreferenced
/// function or variable symbol is not in the list of variable and
/// function symbols to keep, then that symbol is dropped and will not
/// be part of the resulting table of unreferenced symbol that is
/// built.
///
/// The built tables are accessible from
/// corpus::get_unreferenced_function_symbols() and
/// corpus::get_unreferenced_variable_symbols().
void
corpus::priv::build_unreferenced_symbols_tables()
{
unordered_map<string, bool> refed_funs, refed_vars;
elf_symbol_sptr sym;
for (vector<function_decl*>::const_iterator f = fns.begin();
f != fns.end();
++f)
if ((sym = (*f)->get_symbol()))
{
refed_funs[sym->get_id_string()] = true;
for (elf_symbol_sptr a = sym->get_next_alias();
a && !a->is_main_symbol();
a = a->get_next_alias())
refed_funs[a->get_id_string()] = true;
}
for (vector<var_decl*>::const_iterator v = vars.begin();
v != vars.end();
++v)
if ((sym = (*v)->get_symbol()))
{
refed_vars[sym->get_id_string()] = true;
for (elf_symbol_sptr a = sym->get_next_alias();
a && !a->is_main_symbol();
a = a->get_next_alias())
refed_vars[a->get_id_string()] = true;
}
if (fun_symbol_map)
{
// Let's assume that the size of the unreferenced symbols vector
// is roughly smaller than the size of the symbol table.
unrefed_fun_symbols.reserve(fun_symbol_map->size());
for (string_elf_symbols_map_type::const_iterator i
= fun_symbol_map->begin();
i != fun_symbol_map->end();
++i)
for (elf_symbols::const_iterator s = i->second.begin();
s != i->second.end();
++s)
{
string sym_id = (*s)->get_id_string();
if (refed_funs.find(sym_id) == refed_funs.end())
{
bool keep = sym_id_fns_to_keep.empty();
for (vector<string>::const_iterator i =
sym_id_fns_to_keep.begin();
i != sym_id_fns_to_keep.end();
++i)
{
if (*i == sym_id)
{
keep = true;
break;
}
}
if (keep)
unrefed_fun_symbols.push_back(*s);
}
}
comp_elf_symbols_functor comp;
std::sort(unrefed_fun_symbols.begin(),
unrefed_fun_symbols.end(),
comp);
}
if (var_symbol_map)
{
// Let's assume that the size of the unreferenced symbols vector
// is roughly smaller than the size of the symbol table.
unrefed_var_symbols.reserve(var_symbol_map->size());
for (string_elf_symbols_map_type::const_iterator i
= var_symbol_map->begin();
i != var_symbol_map->end();
++i)
for (elf_symbols::const_iterator s = i->second.begin();
s != i->second.end();
++s)
{
string sym_id = (*s)->get_id_string();
if (refed_vars.find(sym_id) == refed_vars.end())
{
bool keep = sym_id_vars_to_keep.empty();
for (vector<string>::const_iterator i =
sym_id_vars_to_keep.begin();
i != sym_id_vars_to_keep.end();
++i)
{
if (*i == sym_id)
{
keep = true;
break;
}
}
if (keep)
unrefed_var_symbols.push_back(*s);
}
}
comp_elf_symbols_functor comp;
std::sort(unrefed_var_symbols.begin(),
unrefed_var_symbols.end(),
comp);
}
}
/// Get the maps that associate a name to a certain kind of type.
type_maps&
corpus::priv::get_types()
{return types_;}
/// Get the maps that associate a name to a certain kind of type.
const type_maps&
corpus::priv::get_types() const
{return types_;}
/// Getter of the set of pretty representation of types that are
/// reachable from public interfaces (global functions and variables).
///
/// @return the set of pretty representation of types that are
/// reachable from public interfaces (global functions and variables).
unordered_set<interned_string, hash_interned_string>*
corpus::priv::get_public_types_pretty_representations()
{
if (group)
return group->get_public_types_pretty_representations();
if (pub_type_pretty_reprs_ == 0)
pub_type_pretty_reprs_ =
new unordered_set<interned_string, hash_interned_string>;
return pub_type_pretty_reprs_;
}
/// Destructor of the @ref corpus::priv type.
corpus::priv::~priv()
{
delete pub_type_pretty_reprs_;
}
/// Constructor of the @ref corpus type.
///
/// @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)
{priv_.reset(new priv(path, env));}
/// Getter of the enviroment of the corpus.
///
/// @return the environment of this corpus.
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) const
{priv_->env = e;}
/// 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.
///
/// Note that two translation units with the same path (as returned by
/// translation_unit::get_path) cannot be added to the same @ref
/// corpus. If that happens, the library aborts.
///
/// @param tu the new translation unit to add.
void
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())
{
// Update the path -> translation_unit map.
string_tu_map_type::const_iterator i =
priv_->path_tu_map.find(tu->get_absolute_path());
ABG_ASSERT(i == priv_->path_tu_map.end());
priv_->path_tu_map[tu->get_absolute_path()] = tu;
}
tu->set_corpus(this);
}
/// Return the list of translation units of the current corpus.
///
/// @return the list of translation units of the current corpus.
const translation_units&
corpus::get_translation_units() const
{return priv_->members;}
/// Find the translation unit that has a given path.
///
/// @param path the path of the translation unit to look for.
///
/// @return the translation unit found, if any. Otherwise, return
/// nil.
const translation_unit_sptr
corpus::find_translation_unit(const string &path) const
{
string_tu_map_type::const_iterator i =
priv_->path_tu_map.find(path);
if (i == priv_->path_tu_map.end())
return translation_unit_sptr();
return i->second;
}
/// Erase the translation units contained in this in-memory object.
///
/// Note that the on-disk archive file that contains the serialized
/// representation of this object is not modified.
void
corpus::drop_translation_units()
{priv_->members.clear();}
/// Get the maps that associate a name to a certain kind of type.
///
/// @return the maps that associate a name to a certain kind of type.
type_maps&
corpus::get_types()
{return priv_->types_;}
/// Get the maps that associate a name to a certain kind of type.
///
/// @return the maps that associate a name to a certain kind of
/// type.
const type_maps&
corpus::get_types() const
{return priv_->types_;}
/// Get the maps that associate a location string to a certain kind of
/// type.
///
/// The location string is the result of the invocation to the
/// function abigail::ir::location::expand(). It has the form
/// "file.c:4:1", with 'file.c' being the file name, '4' being the
/// line number and '1' being the column number.
///
/// @return the maps.
const type_maps&
corpus::get_type_per_loc_map() const
{return priv_->type_per_loc_map_;}
/// Test if the recording of reachable types (and thus, indirectly,
/// the recording of non-reachable types) is activated for the
/// current @ref corpus.
///
/// @return true iff the recording of reachable types is activated for
/// the current @ref corpus.
bool
corpus::recording_types_reachable_from_public_interface_supported()
{
return (priv_->get_public_types_pretty_representations()
&& !priv_->get_public_types_pretty_representations()->empty());
}
/// Record a type as being reachable from public interfaces (global
/// functions and variables).
///
/// @param t the type to record as reachable.
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);
priv_->get_public_types_pretty_representations()->insert(s);
}
/// Test if a type is reachable from public interfaces (global
/// functions and variables).
///
/// For a type to be considered reachable from public interfaces, it
/// must have been previously marked as such by calling
/// corpus::record_type_as_reachable_from_public_interfaces.
///
/// @param t the type to test for.
///
/// @return true iff @p t is reachable from public interfaces.
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);
return (priv_->get_public_types_pretty_representations()->find(s)
!= priv_->get_public_types_pretty_representations()->end());
}
/// Getter of a sorted vector of the types that are *NOT* reachable
/// from public interfaces.
///
/// Note that for this to be non-empty, the libabigail reader that
/// analyzed the input (be it a binary or an abixml file) must have be
/// configured to load types that are not reachable from public
/// interfaces.
///
/// @return a reference to a vector of sorted types NON reachable from
/// public interfaces.
const vector<type_base_wptr>&
corpus::get_types_not_reachable_from_public_interfaces() const
{
if (priv_->types_not_reachable_from_pub_ifaces_.empty())
{
const type_maps& types = get_types();
for (vector<type_base_wptr>::const_iterator it =
types.get_types_sorted_by_name().begin();
it != types.get_types_sorted_by_name().end();
++it)
{
type_base_sptr t(*it);
if (!type_is_reachable_from_public_interfaces(*t))
priv_->types_not_reachable_from_pub_ifaces_.push_back(t);
}
}
return priv_->types_not_reachable_from_pub_ifaces_;
}
/// Get the maps that associate a location string to a certain kind of
/// type.
///
/// The location string is the result of the invocation to the
/// function abigail::ir::location::expand(). It has the form
/// "file.c:4:1", with 'file.c' being the file name, '4' being the
/// line number and '1' being the column number.
///
/// @return the maps.
type_maps&
corpus::get_type_per_loc_map()
{return priv_->type_per_loc_map_;}
/// Getter of the group this corpus is a member of.
///
/// @return the group this corpus is a member of, or nil if it's not
/// part of any @ref corpus_group.
const corpus_group*
corpus::get_group() const
{return priv_->group;}
/// Getter of the group this corpus belongs to.
///
/// @return the group this corpus belong to, or nil if it's not part
/// of any @ref corpus_group.
corpus_group*
corpus::get_group()
{return priv_->group;}
/// Setter of the group this corpus belongs to.
///
/// @param g the new group.
void
corpus::set_group(corpus_group* g)
{priv_->group = g;}
/// Getter for the origin of the corpus.
///
/// @return the origin of the corpus.
corpus::origin
corpus::get_origin() const
{return priv_->origin_;}
/// Setter for the origin of the corpus.
///
/// @param o the new origin for the corpus.
void
corpus::set_origin(origin o)
{priv_->origin_ = o;}
/// Get the file path associated to the corpus file.
///
/// A subsequent call to corpus::read will deserialize the content of
/// the abi file expected at this path; likewise, a call to
/// corpus::write will serialize the translation units contained in
/// the corpus object into the on-disk file at this path.
///
/// @return the file path associated to the current corpus.
string&
corpus::get_path() const
{return priv_->path;}
/// Set the file path associated to the corpus file.
///
/// A subsequent call to corpus::read will deserialize the content of
/// the abi file expected at this path; likewise, a call to
/// corpus::write will serialize the translation units contained in
/// the corpus object into the on-disk file at this path.
///
/// @param path the new file path to assciate to the current corpus.
void
corpus::set_path(const string& path)
{priv_->path = path;}
/// Getter of the needed property of the corpus.
///
/// This property is meaningful for, e.g, corpora built from ELF
/// shared library files. In that case, this is a vector of names of
/// dependencies of the ELF shared library file.
///
/// @return the vector of dependencies needed by this corpus.
const vector<string>&
corpus::get_needed() const
{return priv_->needed;}
/// Setter of the needed property of the corpus.
///
/// This property is meaningful for, e.g, corpora built from ELF
/// shared library files. In that case, this is a vector of names of
/// dependencies of the ELF shared library file.
///
/// @param needed the new vector of dependencies needed by this
/// corpus.
void
corpus::set_needed(const vector<string>& needed)
{priv_->needed = needed;}
/// Getter for the soname property of the corpus.
///
/// This property is meaningful for, e.g, corpora built from ELF
/// shared library files. In that case, this is the shared object
/// name exported by the shared library.
///
/// @return the soname property of the corpus.
const string&
corpus::get_soname()
{return priv_->soname;}
/// Setter for the soname property of the corpus.
///
/// This property is meaningful for, e.g, corpora built from ELF
/// shared library files. In that case, this is the shared object
/// name exported by the shared library.
///
/// @param soname the new soname property of the corpus.
void
corpus::set_soname(const string& soname)
{priv_->soname = soname;}
/// Getter for the architecture name of the corpus.
///
/// This property is meaningful for e.g, corpora built from ELF shared
/// library files. In that case, this is a string representation of
/// the Elf{32,64}_Ehdr::e_machine field.
///
/// @return the architecture name string.
const string&
corpus::get_architecture_name() const
{return priv_->architecture_name;}
/// Setter for the architecture name of the corpus.
///
/// This property is meaningful for e.g, corpora built from ELF shared
/// library files. In that case, this is a string representation of
/// the Elf{32,64}_Ehdr::e_machine field.
///
/// @param arch the architecture name string.
void
corpus::set_architecture_name(const string& arch)
{priv_->architecture_name = arch;}
/// Tests if the corpus is empty from an ABI surface perspective. I.e. if all
/// of these criteria are true:
/// - all translation units (members) are empty
/// - the maps function and variable symbols are not having entries
/// - for shared libraries:
/// - the soname is empty
/// - there are no DT_NEEDED entries
///
/// @return true if the corpus contains no translation unit.
bool
corpus::is_empty() const
{
bool members_empty = true;
for (translation_units::const_iterator i = priv_->members.begin(),
e = priv_->members.end();
i != e; ++i)
{
if (!(*i)->is_empty())
{
members_empty = false;
break;
}
}
return (members_empty
&& priv_->fun_symbol_map
&& priv_->fun_symbol_map->empty()
&& priv_->var_symbol_map
&& priv_->var_symbol_map->empty()
&& priv_->soname.empty()
&& priv_->needed.empty());
}
/// Compare the current @ref corpus against another one.
///
/// @param other the other corpus to compare against.
///
/// @return true if the two corpus are equal, false otherwise.
bool
corpus::operator==(const corpus& other) const
{
translation_units::const_iterator i, j;
for (i = get_translation_units().begin(),
j = other.get_translation_units().begin();
(i != get_translation_units().end()
&& j != other.get_translation_units().end());
++i, ++j)
if ((**i) != (**j))
return false;
return (i == get_translation_units().end()
&& j == other.get_translation_units().end());
}
/// Setter of the function symbols map.
///
/// @param map a shared pointer to the new function symbols map.
void
corpus::set_fun_symbol_map(string_elf_symbols_map_sptr map)
{priv_->fun_symbol_map = map;}
/// Setter for the map of function symbols that are undefined in this
/// corpus.
///
/// @param map a new map for function symbols not defined in this
/// corpus. The key of the map is the name of the function symbol.
/// The value is a vector of all the function symbols that have the
/// same name.
void
corpus::set_undefined_fun_symbol_map(string_elf_symbols_map_sptr map)
{priv_->undefined_fun_symbol_map = map;}
/// Setter of the variable symbols map.
///
/// @param map a shared pointer to the new variable symbols map.
void
corpus::set_var_symbol_map(string_elf_symbols_map_sptr map)
{priv_->var_symbol_map = map;}
/// Setter for the map of variable symbols that are undefined in this
/// corpus.
///
/// @param map a new map for variable symbols not defined in this
/// corpus. The key of the map is the name of the variable symbol.
/// The value is a vector of all the variable symbols that have the
/// same name.
void
corpus::set_undefined_var_symbol_map(string_elf_symbols_map_sptr map)
{priv_->undefined_var_symbol_map = map;}
/// Getter for the function symbols map.
///
/// @return a shared pointer to the function symbols map.
const string_elf_symbols_map_sptr
corpus::get_fun_symbol_map_sptr() const
{
if (!priv_->fun_symbol_map)
priv_->fun_symbol_map.reset(new string_elf_symbols_map_type);
return priv_->fun_symbol_map;
}
/// Getter for the function symbols map.
///
/// @return a reference to the function symbols map.
const string_elf_symbols_map_type&
corpus::get_fun_symbol_map() const
{return *get_fun_symbol_map_sptr();}
/// Getter for the map of function symbols that are undefined in this
/// corpus.
///
/// @return the map of function symbols not defined in this corpus.
/// The key of the map is the name of the function symbol. The value
/// is a vector of all the function symbols that have the same name.
const string_elf_symbols_map_sptr
corpus::get_undefined_fun_symbol_map_sptr() const
{return priv_->undefined_fun_symbol_map;}
/// Getter for the map of function symbols that are undefined in this
/// corpus.
///
/// @return the map of function symbols not defined in this corpus.
/// The key of the map is the name of the function symbol. The value
/// is a vector of all the function symbols that have the same name.
const string_elf_symbols_map_type&
corpus::get_undefined_fun_symbol_map() const
{return *get_undefined_fun_symbol_map_sptr();}
/// Functor to sort instances of @ref elf_symbol.
struct elf_symbol_comp_functor
{
/// Return true if the first argument is less than the second one.
///
/// @param l the first parameter to consider.
///
/// @param r the second parameter to consider.
///
/// @return true if @p l is less than @p r
bool
operator()(elf_symbol& l, elf_symbol& r)
{return (l.get_id_string() < r.get_id_string());}
/// Return true if the first argument is less than the second one.
///
/// @param l the first parameter to consider.
///
/// @param r the second parameter to consider.
///
/// @return true if @p l is less than @p r
bool
operator()(elf_symbol* l, elf_symbol* r)
{return operator()(*l, *r);}
/// Return true if the first argument is less than the second one.
///
/// @param l the first parameter to consider.
///
/// @param r the second parameter to consider.
///
/// @return true if @p l is less than @p r
bool
operator()(elf_symbol_sptr l, elf_symbol_sptr r)
{return operator()(*l, *r);}
}; // end struct elf_symbol_comp_functor
/// Return a sorted vector of function symbols for this corpus.
///
/// Note that the first time this function is called, the symbols are
/// sorted and cached. Subsequent invocations of this function return
/// the cached vector that was built previously.
///
/// @return the sorted list of function symbols.
const elf_symbols&
corpus::get_sorted_fun_symbols() const
{
if (priv_->sorted_fun_symbols.empty()
&& !get_fun_symbol_map().empty())
{
priv_->sorted_fun_symbols.reserve(get_fun_symbol_map().size());
for (string_elf_symbols_map_type::const_iterator i =
get_fun_symbol_map().begin();
i != get_fun_symbol_map().end();
++i)
for (elf_symbols::const_iterator s = i->second.begin();
s != i->second.end();
++s)
priv_->sorted_fun_symbols.push_back(*s);
elf_symbol_comp_functor comp;
std::sort(priv_->sorted_fun_symbols.begin(),
priv_->sorted_fun_symbols.end(),
comp);
}
return priv_->sorted_fun_symbols;
}
/// Getter for a sorted vector of the function symbols undefined in
/// this corpus.
///
/// @return a vector of the function symbols undefined in this corpus,
/// sorted by name and then version.
const elf_symbols&
corpus::get_sorted_undefined_fun_symbols() const
{
if (priv_->sorted_undefined_fun_symbols.empty()
&& !get_undefined_fun_symbol_map().empty())
{
priv_->sorted_undefined_fun_symbols.reserve
(get_undefined_fun_symbol_map().size());
for (string_elf_symbols_map_type::const_iterator i =
get_undefined_fun_symbol_map().begin();
i != get_undefined_fun_symbol_map().end();
++i)
for (elf_symbols::const_iterator s = i->second.begin();
s != i->second.end();
++s)
priv_->sorted_undefined_fun_symbols.push_back(*s);
elf_symbol_comp_functor comp;
std::sort(priv_->sorted_undefined_fun_symbols.begin(),
priv_->sorted_undefined_fun_symbols.end(),
comp);
}
return priv_->sorted_undefined_fun_symbols;
}
/// Getter for the variable symbols map.
///
/// @return a shared pointer to the variable symbols map.
const string_elf_symbols_map_sptr
corpus::get_var_symbol_map_sptr() const
{
if (!priv_->var_symbol_map)
priv_->var_symbol_map.reset(new string_elf_symbols_map_type);
return priv_->var_symbol_map;
}
/// Getter for the variable symbols map.
///
/// @return a reference to the variabl symbols map.
const string_elf_symbols_map_type&
corpus::get_var_symbol_map() const
{return *get_var_symbol_map_sptr();}
/// Getter for the map of variable symbols that are undefined in this
/// corpus.
///
/// @return the map of variable symbols not defined in this corpus.
/// The key of the map is the name of the variable symbol. The value
/// is a vector of all the variable symbols that have the same name.
const string_elf_symbols_map_sptr
corpus::get_undefined_var_symbol_map_sptr() const
{return priv_->undefined_var_symbol_map;}
/// Getter for the map of variable symbols that are undefined in this
/// corpus.
///
/// @return the map of variable symbols not defined in this corpus.
/// The key of the map is the name of the variable symbol. The value
/// is a vector of all the variable symbols that have the same name.
const string_elf_symbols_map_type&
corpus::get_undefined_var_symbol_map() const
{return *get_undefined_var_symbol_map_sptr();}
/// Getter for the sorted vector of variable symbols for this corpus.
///
/// Note that the first time this function is called, it computes the
/// sorted vector, caches the result and returns it. Subsequent
/// invocations of this function just return the cached vector.
///
/// @return the sorted vector of variable symbols for this corpus.
const elf_symbols&
corpus::get_sorted_var_symbols() const
{
if (priv_->sorted_var_symbols.empty()
&& !get_var_symbol_map().empty())
{
priv_->sorted_var_symbols.reserve(get_var_symbol_map().size());
for (string_elf_symbols_map_type::const_iterator i =
get_var_symbol_map().begin();
i != get_var_symbol_map().end();
++i)
for (elf_symbols::const_iterator s = i->second.begin();
s != i->second.end(); ++s)
priv_->sorted_var_symbols.push_back(*s);
elf_symbol_comp_functor comp;
std::sort(priv_->sorted_var_symbols.begin(),
priv_->sorted_var_symbols.end(),
comp);
}
return priv_->sorted_var_symbols;
}
/// Getter for a sorted vector of the variable symbols undefined in
/// this corpus.
///
/// @return a vector of the variable symbols undefined in this corpus,
/// sorted by name and then version.
const elf_symbols&
corpus::get_sorted_undefined_var_symbols() const
{
if (priv_->sorted_undefined_var_symbols.empty()
&& !get_undefined_var_symbol_map().empty())
{
priv_->sorted_undefined_var_symbols.reserve
(get_undefined_var_symbol_map().size());
for (string_elf_symbols_map_type::const_iterator i =
get_undefined_var_symbol_map().begin();
i != get_undefined_var_symbol_map().end();
++i)
for (elf_symbols::const_iterator s = i->second.begin();
s != i->second.end(); ++s)
priv_->sorted_undefined_var_symbols.push_back(*s);
elf_symbol_comp_functor comp;
std::sort(priv_->sorted_undefined_var_symbols.begin(),
priv_->sorted_undefined_var_symbols.end(),
comp);
}
return priv_->sorted_undefined_var_symbols;
}
/// Look in the function symbols map for a symbol with a given name.
///
/// @param n the name of the symbol to look for.
///
/// return the first symbol with the name @p n.
const elf_symbol_sptr
corpus::lookup_function_symbol(const string& n) const
{
if (get_fun_symbol_map().empty())
return elf_symbol_sptr();
string_elf_symbols_map_type::const_iterator it =
get_fun_symbol_map().find(n);
if ( it == get_fun_symbol_map().end())
return elf_symbol_sptr();
return it->second[0];
}
/// Look into a set of symbols and look for a symbol that has a given
/// version.
///
/// This is a sub-routine for corpus::lookup_function_symbol() and
/// corpus::lookup_variable_symbol().
///
/// @param version the version of the symbol to look for.
///
/// @param symbols the set of symbols to consider.
///
/// @return the symbol found, or nil if none was found.
static const elf_symbol_sptr
find_symbol_by_version(const elf_symbol::version& version,
const vector<elf_symbol_sptr>& symbols)
{
if (version.is_empty())
{
// We are looing for a symbol with no version.
// So first look for possible aliases with no version
for (elf_symbols::const_iterator s = symbols.begin();
s != symbols.end();
++s)
if ((*s)->get_version().is_empty())
return *s;
// Or, look for a version that is a default one!
for (elf_symbols::const_iterator s = symbols.begin();
s != symbols.end();
++s)
if ((*s)->get_version().is_default())
return *s;
}
else
// We are looking for a symbol with a particular defined version.
for (elf_symbols::const_iterator s = symbols.begin();
s != symbols.end();
++s)
if ((*s)->get_version().str() == version.str())
return *s;
return elf_symbol_sptr();
}
/// Look in the function symbols map for a symbol with a given name.
///
/// @param symbol_name the name of the symbol to look for.
///
/// @param version the version of the symbol to look for.
///
/// return the symbol with name @p symbol_name and with version @p
/// version, or nil if no symbol has been found with that name and
/// version.
const elf_symbol_sptr
corpus::lookup_function_symbol(const string& symbol_name,
const elf_symbol::version& version) const
{
if (get_fun_symbol_map().empty())
return elf_symbol_sptr();
string_elf_symbols_map_type::const_iterator it =
get_fun_symbol_map().find(symbol_name);
if ( it == get_fun_symbol_map().end())
return elf_symbol_sptr();
return find_symbol_by_version(version, it->second);
}
/// Look in the function symbols map for a symbol with the same name
/// and version as a given symbol.
///
/// @param symbol the symbol to look for.
///
/// return the symbol with the same name and version as @p symbol.
const elf_symbol_sptr
corpus::lookup_function_symbol(const elf_symbol& symbol) const
{return lookup_function_symbol(symbol.get_name(), symbol.get_version());}
/// Look in the variable symbols map for a symbol with a given name.
///
/// @param n the name of the symbol to look for.
///
/// return the first symbol with the name @p n.
const elf_symbol_sptr
corpus::lookup_variable_symbol(const string& n) const
{
if (get_var_symbol_map().empty())
return elf_symbol_sptr();
string_elf_symbols_map_type::const_iterator it =
get_var_symbol_map().find(n);
if ( it == get_var_symbol_map().end())
return elf_symbol_sptr();
return it->second[0];
}
/// Look in the variable symbols map for a symbol with a given name.
///
/// @param symbol_name the name of the symbol to look for.
///
/// @param symbol_version the version of the symbol to look for.
///
/// return the first symbol with the name @p symbol_name and with
/// version @p version.
const elf_symbol_sptr
corpus::lookup_variable_symbol(const string& symbol_name,
const elf_symbol::version& version) const
{
if (get_var_symbol_map().empty())
return elf_symbol_sptr();
string_elf_symbols_map_type::const_iterator it =
get_var_symbol_map().find(symbol_name);
if ( it == get_var_symbol_map().end())
return elf_symbol_sptr();
return find_symbol_by_version(version, it->second);
}
/// Look in the variable symbols map for a symbol with the same name
/// and version as a given symbol.
///
/// @param symbol the symbol to look for.
///
/// return the symbol with the same name and version as @p symbol.
const elf_symbol_sptr
corpus::lookup_variable_symbol(const elf_symbol& symbol) const
{return lookup_variable_symbol(symbol.get_name(), symbol.get_version());}
/// Return the functions public decl table of the current corpus.
///
/// The function public decl tables is a vector of all the functions
/// and member functions found in the current corpus.
///
/// Note that the caller can suppress some functions from the vector
/// supplying regular expressions describing the set of functions she
/// want to see removed from the public decl table by populating the
/// vector of regular expressions returned by
/// corpus::get_regex_patterns_of_fns_to_suppress().
///
/// @return the vector of functions of the public decl table. The
/// functions are sorted using their mangled name or name if they
/// don't have mangle names.
const corpus::functions&
corpus::get_functions() const
{return priv_->fns;}
/// Lookup the function which has a given function ID.
///
/// Note that there can have been several functions with the same ID.
/// This is because debug info can declare the same function in
/// several different translation units. Normally, all these function
/// should be equal. But still, this function returns all these
/// functions.
///
/// @param id the ID of the function to lookup. This ID must be
/// either the result of invoking function::get_id() of
/// elf_symbol::get_id_string().
///
/// @return the vector functions which ID is @p id, or nil if no
/// function with that ID was found.
const vector<function_decl*>*
corpus::lookup_functions(const string& id) const
{
exported_decls_builder_sptr b = get_exported_decls_builder();
str_fn_ptrs_map_type::const_iterator i =
b->priv_->id_fns_map_.find(id);
if (i == b->priv_->id_fns_map_.end())
return 0;
return &i->second;
}
/// Sort the set of functions exported by this corpus.
///
/// Normally, you shouldn't be calling this as the code that creates
/// the corpus for you should do it for you too.
void
corpus::sort_functions()
{
func_comp fc;
std::sort(priv_->fns.begin(), priv_->fns.end(), fc);
}
/// Return the public decl table of the global variables of the
/// current corpus.
///
/// The variable public decls table is a vector of all the public
/// global variables and static member variables found in the current
/// corpus.
///
/// Note that the caller can suppress some variables from the vector
/// supplying regular expressions describing the set of variables she
/// wants to see removed from the public decl table by populating the
/// vector of regular expressions returned by
/// corpus::get_regex_patterns_of_fns_to_suppress().
///
/// @return the vector of variables of the public decl table. The
/// variables are sorted using their name.
const corpus::variables&
corpus::get_variables() const
{return priv_->vars;}
/// Sort the set of variables exported by this corpus.
///
/// Normally, you shouldn't be calling this as the code that creates
/// the corpus for you should do it for you too.
void
corpus::sort_variables()
{
var_comp vc;
std::sort(priv_->vars.begin(), priv_->vars.end(), vc);
}
/// Getter of the set of function symbols that are not referenced by
/// any function exported by the current corpus.
///
/// When the corpus has been created from an ELF library or program,
/// this function returns the set of function symbols not referenced
/// by any debug information.
///
/// @return the vector of function symbols not referenced by any
/// function exported by the current corpus.
const elf_symbols&
corpus::get_unreferenced_function_symbols() const
{
if (priv_->unrefed_fun_symbols.empty()
&& priv_->unrefed_var_symbols.empty())
priv_->build_unreferenced_symbols_tables();
return priv_->unrefed_fun_symbols;
}
/// Getter of the set of variable symbols that are not referenced by
/// any variable exported by the current corpus.
///
/// When the corpus has been created from an ELF library or program,
/// this function returns the set of variable symbols not referenced
/// by any debug information.
///
/// @return the vector of variable symbols not referenced by any
/// variable exported by the current corpus.
const elf_symbols&
corpus::get_unreferenced_variable_symbols() const
{
if (priv_->unrefed_fun_symbols.empty()
&& priv_->unrefed_var_symbols.empty())
priv_->build_unreferenced_symbols_tables();
return priv_->unrefed_var_symbols;
}
/// Accessor for the regex patterns describing the functions to drop
/// from the public decl table.
///
/// @return the regex patterns describing the functions to drop from
/// the public decl table.
vector<string>&
corpus::get_regex_patterns_of_fns_to_suppress()
{return priv_->regex_patterns_fns_to_suppress;}
/// Accessor for the regex patterns describing the functions to drop
/// from the public decl table.
///
/// @return the regex patterns describing the functions to drop from
/// the public decl table.
const vector<string>&
corpus::get_regex_patterns_of_fns_to_suppress() const
{return priv_->regex_patterns_fns_to_suppress;}
/// Accessor for the regex patterns describing the variables to drop
/// from the public decl table.
///
/// @return the regex patterns describing the variables to drop from
/// the public decl table.
vector<string>&
corpus::get_regex_patterns_of_vars_to_suppress()
{return priv_->regex_patterns_vars_to_suppress;}
/// Accessor for the regex patterns describing the variables to drop
/// from the public decl table.
///
/// @return the regex patterns describing the variables to drop from
/// the public decl table.
const vector<string>&
corpus::get_regex_patterns_of_vars_to_suppress() const
{return priv_->regex_patterns_vars_to_suppress;}
/// Accessor for the regex patterns describing the functions to keep
/// into the public decl table. The other functions not matches by these
/// regexes are dropped from the public decl table.
///
/// @return the regex patterns describing the functions to keep into
/// the public decl table.
vector<string>&
corpus::get_regex_patterns_of_fns_to_keep()
{return priv_->regex_patterns_fns_to_keep;}
/// Accessor for the regex patterns describing the functions to keep
/// into the public decl table. The other functions not matches by these
/// regexes are dropped from the public decl table.
///
/// @return the regex patterns describing the functions to keep into
/// the public decl table.
const vector<string>&
corpus::get_regex_patterns_of_fns_to_keep() const
{return priv_->regex_patterns_fns_to_keep;}
/// Getter for the vector of function symbol IDs to keep.
///
/// A symbol ID is a string made of the name of the symbol and its
/// version, separated by one or two '@'.
///
/// @return a vector of IDs of function symbols to keep.
vector<string>&
corpus::get_sym_ids_of_fns_to_keep()
{return priv_->sym_id_fns_to_keep;}
/// Getter for the vector of function symbol IDs to keep.
///
/// A symbol ID is a string made of the name of the symbol and its
/// version, separated by one or two '@'.
///
/// @return a vector of IDs of function symbols to keep.
const vector<string>&
corpus::get_sym_ids_of_fns_to_keep() const
{return priv_->sym_id_fns_to_keep;}
/// Accessor for the regex patterns describing the variables to keep
/// into the public decl table. The other variables not matches by these
/// regexes are dropped from the public decl table.
///
/// @return the regex patterns describing the variables to keep into
/// the public decl table.
vector<string>&
corpus::get_regex_patterns_of_vars_to_keep()
{return priv_->regex_patterns_vars_to_keep;}
/// Accessor for the regex patterns describing the variables to keep
/// into the public decl table. The other variables not matches by these
/// regexes are dropped from the public decl table.
///
/// @return the regex patterns describing the variables to keep into
/// the public decl table.
const vector<string>&
corpus::get_regex_patterns_of_vars_to_keep() const
{return priv_->regex_patterns_vars_to_keep;}
/// Getter for the vector of variable symbol IDs to keep.
///
/// A symbol ID is a string made of the name of the symbol and its
/// version, separated by one or two '@'.
///
/// @return a vector of IDs of variable symbols to keep.
vector<string>&
corpus::get_sym_ids_of_vars_to_keep()
{return priv_->sym_id_vars_to_keep;}
/// Getter for the vector of variable symbol IDs to keep.
///
/// A symbol ID is a string made of the name of the symbol and its
/// version, separated by one or two '@'.
///
/// @return a vector of IDs of variable symbols to keep.
const vector<string>&
corpus::get_sym_ids_of_vars_to_keep() const
{return priv_->sym_id_vars_to_keep;}
/// After the set of exported functions and variables have been built,
/// consider all the tunables that control that set and see if some
/// functions need to be removed from that set; if so, remove them.
void
corpus::maybe_drop_some_exported_decls()
{
string sym_name, sym_version;
vector<function_decl*> fns_to_keep;
exported_decls_builder* b = get_exported_decls_builder().get();
for (vector<function_decl*>::iterator f = priv_->fns.begin();
f != priv_->fns.end();
++f)
{
if (b->priv_->keep_wrt_id_of_fns_to_keep(*f)
&& b->priv_->keep_wrt_regex_of_fns_to_suppress(*f)
&& b->priv_->keep_wrt_regex_of_fns_to_keep(*f))
fns_to_keep.push_back(*f);
}
priv_->fns = fns_to_keep;
vector<var_decl*> vars_to_keep;
for (vector<var_decl*>::iterator v = priv_->vars.begin();
v != priv_->vars.end();
++v)
{
if (b->priv_->keep_wrt_id_of_vars_to_keep(*v)
&& b->priv_->keep_wrt_regex_of_vars_to_suppress(*v)
&& b->priv_->keep_wrt_regex_of_vars_to_keep(*v))
vars_to_keep.push_back(*v);
}
priv_->vars = vars_to_keep;
}
/// Getter for the object that is responsible for determining what
/// decls ought to be in the set of exported decls.
///
/// The object does have methods to add the decls to the set of
/// exported decls, right at the place where the corpus expects it,
/// so that there is no unnecessary copying involved.
///
/// @return a (smart) pointer to the instance of @ref
/// corpus::exported_decls_builder that is responsible for determine
/// what decls ought to be in the set of exported decls.
corpus::exported_decls_builder_sptr
corpus::get_exported_decls_builder() const
{
if (!priv_->exported_decls_builder)
{
priv_->exported_decls_builder.reset
(new exported_decls_builder(priv_->fns,
priv_->vars,
priv_->regex_patterns_fns_to_suppress,
priv_->regex_patterns_vars_to_suppress,
priv_->regex_patterns_fns_to_keep,
priv_->regex_patterns_vars_to_keep,
priv_->sym_id_fns_to_keep,
priv_->sym_id_vars_to_keep));
}
return priv_->exported_decls_builder;
}
// </corpus stuff>
// <corpus_group stuff>
/// Type of the private data of @ref corpus_group
struct corpus_group::priv
{
corpora_type corpora;
istring_function_decl_ptr_map_type fns_map;
vector<function_decl*> fns;
istring_var_decl_ptr_map_type vars_map;
vector<var_decl*> vars;
string_elf_symbols_map_type var_symbol_map;
string_elf_symbols_map_type fun_symbol_map;
elf_symbols sorted_var_symbols;
elf_symbols sorted_fun_symbols;
unordered_map<string, elf_symbol_sptr> unrefed_fun_symbol_map;
elf_symbols unrefed_fun_symbols;
bool unrefed_fun_symbols_built;
unordered_map<string, elf_symbol_sptr> unrefed_var_symbol_map;
elf_symbols unrefed_var_symbols;
bool unrefed_var_symbols_built;
unordered_set<interned_string, hash_interned_string> pub_type_pretty_reprs_;
priv()
: unrefed_fun_symbols_built(),
unrefed_var_symbols_built()
{}
/// Add symbols to the set of corpus group function symbols that are
/// *NOT* referenced by debug info.
///
/// @param syms the set the symbols to add.
void
add_unref_fun_symbols(const elf_symbols& syms)
{
for (elf_symbols::const_iterator e =
syms.begin(); e != syms.end(); ++e)
{
string sym_id = (*e)->get_id_string();
unordered_map<string, elf_symbol_sptr>::const_iterator j =
unrefed_fun_symbol_map.find(sym_id);
if (j != unrefed_fun_symbol_map.end())
continue;
unrefed_fun_symbol_map[sym_id] = *e;
unrefed_fun_symbols.push_back(*e);
}
unrefed_fun_symbols_built = true;
}
/// Add symbols to the set of corpus group variable symbols that are
/// *NOT* referenced by debug info.
///
/// @param syms the set the symbols to add.
void
add_unref_var_symbols(const elf_symbols& syms)
{
for (elf_symbols::const_iterator e =
syms.begin(); e != syms.end(); ++e)
{
string sym_id = (*e)->get_id_string();
unordered_map<string, elf_symbol_sptr>::const_iterator j =
unrefed_var_symbol_map.find(sym_id);
if (j != unrefed_var_symbol_map.end())
continue;
unrefed_var_symbol_map[sym_id] = *e;
unrefed_var_symbols.push_back(*e);
}
unrefed_var_symbols_built = true;
}
}; // end corpus_group::priv
/// Default constructor of the @ref corpus_group type.
corpus_group::corpus_group(environment* env, const string& path = "")
: corpus(env, path), priv_(new priv)
{}
/// Desctructor of the @ref corpus_group type.
corpus_group::~corpus_group()
{}
/// Add a new corpus to the current instance of @ref corpus_group.
///
/// @param corp the new corpus to add.
void
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();
if (cur_arch.empty())
set_architecture_name(corp_arch);
else if (cur_arch != corp_arch)
{
std::cerr << "corpus '" << corp->get_path() << "'"
<< " has architecture '" << corp_arch << "'"
<< " but expected '" << cur_arch << "'\n";
ABG_ASSERT_NOT_REACHED;
}
priv_->corpora.push_back(corp);
corp->set_group(this);
/// Add the unreferenced function and variable symbols of this
/// corpus to the unreferenced symbols of the current corpus group.
priv_->add_unref_fun_symbols(get_unreferenced_function_symbols());
priv_->add_unref_var_symbols(get_unreferenced_variable_symbols());
}
/// Getter of the vector of corpora held by the current @ref
/// corpus_group.
///
/// @return the vector corpora.
const corpus_group::corpora_type&
corpus_group::get_corpora() const
{return priv_->corpora;}
/// Getter of the first corpus added to this Group.
///
/// @return the first corpus added to this Group.
const corpus_sptr
corpus_group::get_main_corpus() const
{return const_cast<corpus_group*>(this)->get_main_corpus();}
/// Getter of the first corpus added to this Group.
///
/// @return the first corpus added to this Group.
corpus_sptr
corpus_group::get_main_corpus()
{
if (!get_corpora().empty())
return get_corpora().front();
return corpus_sptr();
}
/// Test if the current corpus group is empty.
///
/// @return true iff the current corpus group is empty.
bool
corpus_group::is_empty() const
{return get_corpora().empty();}
/// Get the functions exported by the corpora of the current corpus
/// group.
///
/// Upon its first invocation, this function walks the corpora
/// contained in the corpus group and caches the functions they exported.
///
/// Subsequent invocations just return the cached functions.
///
/// @return the exported functions.
const corpus::functions&
corpus_group::get_functions() const
{
if (priv_->fns.empty())
for (corpora_type::const_iterator i = get_corpora().begin();
i != get_corpora().end();
++i)
{
corpus_sptr c = *i;
for (corpus::functions::const_iterator f = c->get_functions().begin();
f != c->get_functions().end();
++f)
{
interned_string fid = (*f)->get_id();
istring_function_decl_ptr_map_type::const_iterator j =
priv_->fns_map.find(fid);
if (j != priv_->fns_map.end())
// Don't cache the same function twice ...
continue;
priv_->fns_map[fid] = *f;
// really cache the function now.
priv_->fns.push_back(*f);
}
}
return priv_->fns;
}
/// Get the global variables exported by the corpora of the current
/// corpus group.
///
/// Upon its first invocation, this function walks the corpora
/// contained in the corpus group and caches the variables they
/// export.
///
/// @return the exported variables.
const corpus::variables&
corpus_group::get_variables() const
{
if (priv_->vars.empty())
for (corpora_type::const_iterator i = get_corpora().begin();
i != get_corpora().end();
++i)
{
corpus_sptr c = *i;
for (corpus::variables::const_iterator v = c->get_variables().begin();
v != c->get_variables().end();
++v)
{
interned_string vid = (*v)->get_id();
istring_var_decl_ptr_map_type::const_iterator j =
priv_->vars_map.find(vid);
if (j != priv_->vars_map.end())
// Don't cache the same variable twice ...
continue;
priv_->vars_map[vid] = *v;
// Really cache the variable now.
priv_->vars.push_back(*v);
}
}
return priv_->vars;
}
/// Get the symbols of the global variables exported by the corpora of
/// the current @ref corpus_group.
///
/// @return the symbols of the global variables exported by the corpora
const string_elf_symbols_map_type&
corpus_group::get_var_symbol_map() const
{
if (priv_->var_symbol_map.empty())
for (corpora_type::const_iterator i = get_corpora().begin();
i != get_corpora().end();
++i)
priv_->var_symbol_map.insert((*i)->get_var_symbol_map().begin(),
(*i)->get_var_symbol_map().end());
return priv_->var_symbol_map;
}
/// Get the symbols of the global functions exported by the corpora of
/// the current @ref corpus_group.
///
/// @return the symbols of the global functions exported by the corpora
const string_elf_symbols_map_type&
corpus_group::get_fun_symbol_map() const
{
if (priv_->fun_symbol_map.empty())
for (corpora_type::const_iterator i = get_corpora().begin();
i != get_corpora().end();
++i)
priv_->fun_symbol_map.insert((*i)->get_fun_symbol_map().begin(),
(*i)->get_fun_symbol_map().end());
return priv_->fun_symbol_map;
}
/// Get a sorted vector of the symbols of the functions exported by
/// the corpora of the current group.
///
/// @return the sorted vectors of the exported function symbols.
const elf_symbols&
corpus_group::get_sorted_fun_symbols() const
{
if (priv_->sorted_fun_symbols.empty()
&& !get_fun_symbol_map().empty())
{
for (corpora_type::const_iterator i = get_corpora().begin();
i != get_corpora().end();
++i)
{
corpus_sptr c = *i;
for (string_elf_symbols_map_type::const_iterator j =
c->get_fun_symbol_map().begin();
j != c->get_fun_symbol_map().begin();
++j)
priv_->sorted_fun_symbols.insert(priv_->sorted_fun_symbols.end(),
j->second.begin(),
j->second.end());
}
comp_elf_symbols_functor comp;
std::sort(priv_->sorted_fun_symbols.begin(),
priv_->sorted_fun_symbols.end(),
comp);
}
return priv_->sorted_fun_symbols;
}
/// Get a sorted vector of the symbols of the variables exported by
/// the corpora of the current group.
///
/// @return the sorted vectors of the exported variable symbols.
const elf_symbols&
corpus_group::get_sorted_var_symbols() const
{
if (priv_->sorted_var_symbols.empty()
&& !get_var_symbol_map().empty())
{
for (corpora_type::const_iterator i = get_corpora().begin();
i != get_corpora().end();
++i)
{
corpus_sptr c = *i;
for (string_elf_symbols_map_type::const_iterator j =
c->get_var_symbol_map().begin();
j != c->get_var_symbol_map().begin();
++j)
priv_->sorted_var_symbols.insert(priv_->sorted_var_symbols.end(),
j->second.begin(),
j->second.end());
}
comp_elf_symbols_functor comp;
std::sort(priv_->sorted_var_symbols.begin(),
priv_->sorted_var_symbols.end(),
comp);
}
return priv_->sorted_var_symbols;
}
/// Get the set of function symbols not referenced by any debug info,
/// from all the corpora of the current corpus group.
///
/// Upon its first invocation, this function possibly walks all the
/// copora of this corpus group and caches the unreferenced symbols
/// they export. The function then returns the cache.
///
/// Upon subsequent invocations, this functions just returns the
/// cached symbols.
///
/// @return the unreferenced symbols.
const elf_symbols&
corpus_group::get_unreferenced_function_symbols() const
{
if (!priv_->unrefed_fun_symbols_built)
if (priv_->unrefed_fun_symbols.empty())
{
for (corpora_type::const_iterator i = get_corpora().begin();
i != get_corpora().end();
++i)
{
corpus_sptr c = *i;
for (elf_symbols::const_iterator e =
c->get_unreferenced_function_symbols().begin();
e != c->get_unreferenced_function_symbols().end();
++e)
{
string sym_id = (*e)->get_id_string();
unordered_map<string, elf_symbol_sptr>::const_iterator j =
priv_->unrefed_fun_symbol_map.find(sym_id);
if (j != priv_->unrefed_fun_symbol_map.end())
continue;
priv_->unrefed_fun_symbol_map[sym_id] = *e;
priv_->unrefed_fun_symbols.push_back(*e);
}
}
priv_->unrefed_fun_symbols_built = true;
}
return priv_->unrefed_fun_symbols;
}
/// Get the set of variable symbols not referenced by any debug info,
/// from all the corpora of the current corpus group.
///
/// Upon its first invocation, this function possibly walks all the
/// copora of this corpus group and caches the unreferenced symbols
/// they export. The function then returns the cache.
///
/// Upon subsequent invocations, this functions just returns the
/// cached symbols.
///
/// @return the unreferenced symbols.
const elf_symbols&
corpus_group::get_unreferenced_variable_symbols() const
{
if (!priv_->unrefed_var_symbols_built)
if (priv_->unrefed_var_symbols.empty())
{
for (corpora_type::const_iterator i = get_corpora().begin();
i != get_corpora().end();
++i)
{
corpus_sptr c = *i;
for (elf_symbols::const_iterator e =
c->get_unreferenced_variable_symbols().begin();
e != c->get_unreferenced_variable_symbols().end();
++e)
{
string sym_id = (*e)->get_id_string();
unordered_map<string, elf_symbol_sptr>::const_iterator j =
priv_->unrefed_var_symbol_map.find(sym_id);
if (j != priv_->unrefed_var_symbol_map.end())
continue;
priv_->unrefed_var_symbol_map[sym_id] = *e;
priv_->unrefed_var_symbols.push_back(*e);
}
}
priv_->unrefed_var_symbols_built = true;
}
return priv_->unrefed_var_symbols;
}
/// Getter of a pointer to the set of types reachable from public
/// interfaces of a given corpus group.
unordered_set<interned_string, hash_interned_string>*
corpus_group::get_public_types_pretty_representations()
{return &priv_->pub_type_pretty_reprs_;}
/// Test if the recording of reachable types (and thus, indirectly,
/// the recording of non-reachable types) is activated for the
/// current @ref corpus_group.
///
/// @return true iff the recording of reachable types is activated for
/// the current @ref corpus_group.
bool
corpus_group::recording_types_reachable_from_public_interface_supported()
{return !get_public_types_pretty_representations()->empty();}
// </corpus_group stuff>
}// end namespace ir
}// end namespace abigail