libabigail/include/abg-corpus.h
Dodji Seketeli c495a5c5f0 Handle per translation unit and per corpus types maps
Today, whenever a type is added to its scope, a map that associates
the qualified type name to the type is updated.  There is only one
such map in a given ABI corpus.

So whenever a type is looked up from its name, it's that per-corpus
type map that is used.

This setup makes libabigail type lookup be tailored only for binaries
that respect the One Definition Rule of C++[1] (aka ODR) which
basically says that there should be only one type of a given name in
an ABI corpus.

It turns out that many binaries, especically C binaries, don't respect
the ODR.  So a type "struct foo" can be defined in a file a.c and
another *different* type "struct foo" can also be defined in b.c.
What a useful and safe feature! Not.

For those binaries, just having one type map doesn't work.  We need to
have one type map per translation unit, and one map per-corpus map.

This is the strategy implemented by this patch.

With this patch, whenever a type is added to its scope, a
per translation unit type map is updated.  The per corpus map is
updated as well.  If there are more than one type of a given name, the
entry in the per corpus type map for that type is left empty.

Type lookup now potentially becomes a two phases lookup.  Whenever a
type is looked up from its name, the per corpus type map is looked at
first.  If the type is not in that per corpus type map, then the per
translation unit type maps are lookup up, in sequence.

The patch thus re-visits the type maps updating and lookup routines to
adapt them to the new scheme.  The patch also updates the clients of
the type map updating and lookup code.

Note that this patch is part of a series of patches which aims to move
libabigails away from its ODR-centric organization to make it work
well also on binary where the ODR is not relevant.  As such, the patch
doesn't assure that "make check" passes.  To have "make check" pass,
you need to have all the patches of the series applied.

[1]: https://en.wikipedia.org/wiki/One_Definition_Rule

	* include/abg-fwd.h (lookup_type_in_corpus): Remove.  This is to
	be replaced by the new lookup_type below.
	(lookup_{basic, class, union, enum, typedef, qualified, pointer,
	reference, array, function, class_or_typedef,
	class_typedef_or_enum}_type):
	(lookup_class_type_through_scopes, lookup_type)
	(lookup_type_through_scopes, lookup_or_synthesize_fn_type)
	* src/abg-ir-priv.h (struct translation_unit::priv):  Move this
	private type here, from abg-ir.h.
	(synthesize_type_from_translation_unit): Declare new functions.
	* include/abg-ir.h (class type_maps): Define new type.
	(translation_unit::get_function_types): Remove.
	(translation_unit::get_types): Now return a type_maps.
	(translation_unit::get_live_fn_types): Declare new type.
	(class decl_base): Make canonicalize be a friend of this class.
	* src/abg-ir.cc (struct translation_unit::priv): Move this to
	abg-ir-priv.h
	(struct type_maps::priv): Define new type.
	(type_maps::{basic, class, union, enum, typedef, qualified,
	pointer, reference, array, function}_types): Define new accessors.
	(translation_unit::bind_function_type_life_time): Adjust.
	(translation_unit::get_function_types): Remove accessor.
	(translation_unit::get_types, get_live_fn_types): Define new
	accessors.
	(lookup_type_in_translation_unit)
	(lookup_class_type_in_translation_unit)
	(lookup_function_type_in_translation_unit)
	(synthesize_type_from_translation_unit)
	(synthesize_function_type_from_translation_unit)
	(lookup_class_type_in_translation_unit) Remove function
	definitions.
	(lookup_type_in_map): Define function template.
	(lookup_{basic, class, union, typedef, class_or_typedef,
	class_typedef_or_enum, qualified, pointer, reference, array,
	function}_type): Define functions.
	(lookup_function_type, lookup_type_through_scopes)
	(lookup_class_type_through_scopes)
	(lookup_basic_type_through_translation_units)
	(lookup_union_type_through_translation_units)
	(lookup_enum_type_through_translation_units)
	(lookup_class_type_through_translation_units)
	(lookup_typedef_type_through_translation_units)
	(lookup_qualified_type_through_translation_units)
	(lookup_pointer_type_through_translation_units)
	(lookup_reference_type_through_translation_units)
	(lookup_array_type_through_translation_units)
	(lookup_function_type_through_translation_units)
	(lookup_type_through_translation_units)
	(lookup_or_synthesize_fn_type, lookup_type): Likewise.
	(maybe_update_types_lookup_map)
	(maybe_update_types_lookup_map<class_decl>)
	(maybe_update_types_lookup_map<function_type>): Define function
	template, specilizations and functions.
	(synthesize_type_from_translation_unit)
	(synthesize_function_type_from_translation_unit): Define
	functions.
	* include/abg-corpus.h (corpus::get_types): Declare new accessor.
	* src/abg-corpus.cc (corpus::priv::get_types): Define new
	accessor.
	(corpus::get_types): Likewise.
	(lookup_type_in_corpus, lookup_class_type_in_corpus)
	(lookup_type_in_corpus, lookup_function_type_in_corpus)
	(maybe_update_types_lookup_map)
	(maybe_update_types_lookup_map<class_decl>)
	(maybe_update_types_lookup_map<function_type>): Remove.
	(lookup_{basic, class, union, enum, typedef, qualified, pointer,
	reference, array, function, class_or_typedef,
	class_typedef_or_enum}_type): Likewise.
	* src/abg-corpus-priv.h (corpus::priv::{basic, class, union,
	typedef, qualified, pointer, reference, array, function}_types):
	Remove these data members.
	(corpus::priv::get_scopes): Remove member function.
	(corpus::priv::get_{basic, class, union, enum, typedef, qualified,
	pointer, reference, array, function}_types): Remove member
	function declarations.
	(corpus::priv::types_): New data member.
	(corpus::priv::get_types): Declare new member function.
	(lookup_{basic, class, enum, typedef, class_or_typedef, qualified,
	pointer, reference, array, function}_type): Declare new functions.
	* src/abg-dwarf-reader.cc
	(read_context::resolve_declaration_only_classes)
	(build_translation_unit_and_add_to_ir): Adjust use of
	lookup_class_type.
	* src/abg-reader.cc (read_context::type_is_from_translation_unit):
	Adjust to the use of lookup_function_type_in_translation_unit that
	got renamed into lookup_function_type.
	* src/abg-writer.cc (type_ptr_cmp::operator()): New operator
	implementation.
	(read_context::sort_type): Add new overloads.
	(write_translation_unit): Adjust to get the function types from
	the new translation_unit::get_live_fn_types and sort them.
	* tools/abicompat.cc (perform_compat_check_in_weak_mode): Adjust
	to use the new lookup_or_synthesize_fn_type, in lieu of
	lookup_function_type_in_corpus.  Adjust to use lookup_type in lieu
	of lookup_type_in_corpus.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2017-01-05 12:18:33 +01:00

335 lines
7.3 KiB
C++

// -*- mode: C++ -*-
//
// Copyright (C) 2013-2016 Red Hat, Inc.
//
// This file is part of the GNU Application Binary Interface Generic
// Analysis and Instrumentation Library (libabigail). This library is
// free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 3, or (at your option) any
// later version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Lesser Public License for more details.
// You should have received a copy of the GNU Lesser General Public
// License along with this program; see the file COPYING-LGPLV3. If
// not, see <http://www.gnu.org/licenses/>.
/// @file
#ifndef __ABG_CORPUS_H__
#define __ABG_CORPUS_H__
#include <abg-ir.h>
namespace abigail
{
namespace ir
{
class corpus;
/// A convenience typedef for shared pointer to @ref corpus.
typedef shared_ptr<corpus> corpus_sptr;
/// This is the abstraction of a set of translation units (themselves
/// seen as bundles of unitary abi artefacts like types and decls)
/// bundled together as a corpus. A corpus is thus the Application
/// binary interface of a program, a library or just a set of modules
/// put together.
class corpus
{
public:
struct priv;
/// Convenience typedef for shared_ptr of corpus::priv
typedef shared_ptr<priv> priv_sptr;
/// A convenience typedef for std::vector<string>.
typedef vector<string> strings_type;
/// Convenience typedef for std::vector<abigail::ir::function_decl*>
typedef vector<function_decl*> functions;
///Convenience typedef for std::vector<abigail::ir::var_decl*>
typedef vector<var_decl*> variables;
class exported_decls_builder;
/// Convenience typedef for shared_ptr<exported_decls_builder>.
typedef shared_ptr<exported_decls_builder> exported_decls_builder_sptr;
/// This abstracts where the corpus comes from. That is, either it
/// has been read from the native xml format, from DWARF or built
/// artificially using the library's API.
enum origin
{
ARTIFICIAL_ORIGIN = 0,
NATIVE_XML_ORIGIN,
DWARF_ORIGIN
};
private:
corpus();
void record_canonical_type(const type_base_sptr&) const;
type_base_sptr lookup_canonical_type(const string& qualified_name) const;
public:
shared_ptr<priv> priv_;
corpus(ir::environment*, const string& path= "");
const environment*
get_environment() const;
environment*
get_environment();
void
set_environment(environment*) const;
void
add(const translation_unit_sptr);
const translation_units&
get_translation_units() const;
void
drop_translation_units();
type_maps&
get_types();
const type_maps&
get_types() const;
origin
get_origin() const;
void
set_origin(origin);
string&
get_path() const;
void
set_path(const string&);
const vector<string>&
get_needed() const;
void
set_needed(const vector<string>&);
const string&
get_soname();
void
set_soname(const string&);
const string&
get_architecture_name();
void
set_architecture_name(const string&);
bool
is_empty() const;
bool
operator==(const corpus&) const;
void
set_fun_symbol_map(string_elf_symbols_map_sptr);
void
set_undefined_fun_symbol_map(string_elf_symbols_map_sptr);
void
set_var_symbol_map(string_elf_symbols_map_sptr);
void
set_undefined_var_symbol_map(string_elf_symbols_map_sptr);
const string_elf_symbols_map_sptr
get_fun_symbol_map_sptr() const;
const string_elf_symbols_map_type&
get_fun_symbol_map() const;
const string_elf_symbols_map_sptr
get_undefined_fun_symbol_map_sptr() const;
const string_elf_symbols_map_type&
get_undefined_fun_symbol_map() const;
const elf_symbols&
get_sorted_fun_symbols() const;
const elf_symbols&
get_sorted_undefined_fun_symbols() const;
const string_elf_symbols_map_sptr
get_var_symbol_map_sptr() const;
const string_elf_symbols_map_type&
get_var_symbol_map() const;
const string_elf_symbols_map_sptr
get_undefined_var_symbol_map_sptr() const;
const string_elf_symbols_map_type&
get_undefined_var_symbol_map() const;
const elf_symbols&
get_sorted_var_symbols() const;
const elf_symbols&
get_sorted_undefined_var_symbols() const;
const elf_symbol_sptr
lookup_function_symbol(const string& n) const;
const elf_symbol_sptr
lookup_function_symbol(const string& symbol_name,
const elf_symbol::version& version) const;
const elf_symbol_sptr
lookup_function_symbol(const elf_symbol& symbol) const;
const elf_symbol_sptr
lookup_variable_symbol(const string& n) const;
const elf_symbol_sptr
lookup_variable_symbol(const string& symbol_name,
const elf_symbol::version& version) const;
const elf_symbol_sptr
lookup_variable_symbol(const elf_symbol& symbol) const;
const functions&
get_functions() const;
const vector<function_decl*>*
lookup_functions(const string& id) const;
void
sort_functions();
const variables&
get_variables() const;
void
sort_variables();
const elf_symbols&
get_unreferenced_function_symbols() const;
const elf_symbols&
get_unreferenced_variable_symbols() const;
vector<string>&
get_regex_patterns_of_fns_to_suppress();
const vector<string>&
get_regex_patterns_of_fns_to_suppress() const;
vector<string>&
get_regex_patterns_of_vars_to_suppress();
const vector<string>&
get_regex_patterns_of_vars_to_suppress() const;
vector<string>&
get_regex_patterns_of_fns_to_keep();
const vector<string>&
get_regex_patterns_of_fns_to_keep() const;
vector<string>&
get_sym_ids_of_fns_to_keep();
const vector<string>&
get_sym_ids_of_fns_to_keep() const;
vector<string>&
get_regex_patterns_of_vars_to_keep();
const vector<string>&
get_regex_patterns_of_vars_to_keep() const;
vector<string>&
get_sym_ids_of_vars_to_keep();
const vector<string>&
get_sym_ids_of_vars_to_keep() const;
void
maybe_drop_some_exported_decls();
exported_decls_builder_sptr
get_exported_decls_builder() const;
friend class type_base;
};// end class corpus.
/// Abstracts the building of the set of exported variables and
/// functions.
///
/// Given a function or variable, this type can decide if it belongs
/// to the list of exported functions and variables based on all the
/// parameters needed.
class corpus::exported_decls_builder
{
public:
class priv;
/// Convenience typedef for shared_ptr<priv>
typedef shared_ptr<priv> priv_sptr;
friend class corpus;
private:
priv_sptr priv_;
// Forbid default construction.
exported_decls_builder();
public:
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);
const functions&
exported_functions() const;
functions&
exported_functions();
const variables&
exported_variables() const;
variables&
exported_variables();
void
maybe_add_fn_to_exported_fns(function_decl*);
void
maybe_add_var_to_exported_vars(var_decl*);
}; //corpus::exported_decls_builder
}// end namespace ir
}//end namespace abigail
#endif //__ABG_CORPUS_H__