// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -*- Mode: C++ -*- // // Copyright (C) 2016-2022 Red Hat, Inc. /// @file /// /// The private data and functions of the @ref abigail::ir::corpus type. /// /// Interfaces declared/defined in this file are to be used by parts /// of libabigail but *NOT* by clients of libabigail. /// #ifndef __ABG_CORPUS_PRIV_H__ #define __ABG_CORPUS_PRIV_H__ #include "abg-internal.h" #include "abg-ir.h" #include "abg-regex.h" #include "abg-sptr-utils.h" #include "abg-symtab-reader.h" namespace abigail { namespace sptr_utils { }// end namespace sptr_utils namespace ir { using regex::regex_t_sptr; /// A convenience typedef for std::vector. typedef vector regex_t_sptrs_type; // /// Convenience typedef for a hash map which key is a string and which /// data is a vector of abigail::ir::function_decl* typedef unordered_map > str_fn_ptrs_map_type; /// Convenience typedef for a hash map which key is a string and /// which data is an abigail::ir::var_decl*. typedef unordered_map str_var_ptr_map_type; /// The type of the private data of @ref /// corpus::exported_decls_builder type. class corpus::exported_decls_builder::priv { friend class corpus::exported_decls_builder; friend class corpus; priv(); functions& fns_; variables& vars_; // A map that associates a function ID (function symbol and its // version) to to a vector of functions with that ID. Normally, one // would think that in the corpus, there must only one function for // a given ID. Actually, in c++, there can be two function template // instantiations that produce the same function ID because the // template parameters of the second instantiation are just typedefs // of the first instantiation, for instance. So there can be cases // where one ID appertains to more than one function. str_fn_ptrs_map_type id_fns_map_; str_var_ptr_map_type id_var_map_; strings_type& fns_suppress_regexps_; regex_t_sptrs_type compiled_fns_suppress_regexp_; strings_type& vars_suppress_regexps_; regex_t_sptrs_type compiled_vars_suppress_regexp_; strings_type& fns_keep_regexps_; regex_t_sptrs_type compiled_fns_keep_regexps_; strings_type& vars_keep_regexps_; regex_t_sptrs_type compiled_vars_keep_regexps_; strings_type& sym_id_of_fns_to_keep_; strings_type& sym_id_of_vars_to_keep_; public: priv(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) : fns_(fns), vars_(vars), fns_suppress_regexps_(fns_suppress_regexps), vars_suppress_regexps_(vars_suppress_regexps), fns_keep_regexps_(fns_keep_regexps), vars_keep_regexps_(vars_keep_regexps), sym_id_of_fns_to_keep_(sym_id_of_fns_to_keep), sym_id_of_vars_to_keep_(sym_id_of_vars_to_keep) {} /// Getter for the compiled regular expressions that designate the /// functions to suppress from the set of exported functions. /// /// @return a vector of the compiled regular expressions. regex_t_sptrs_type& compiled_regex_fns_suppress() { if (compiled_fns_suppress_regexp_.empty()) { for (vector::const_iterator i = fns_suppress_regexps_.begin(); i != fns_suppress_regexps_.end(); ++i) { regex_t_sptr r = regex::compile(*i); if (r) compiled_fns_suppress_regexp_.push_back(r); } } return compiled_fns_suppress_regexp_; } /// Getter for the compiled regular expressions that designates the /// functions to keep in the set of exported functions. /// /// @return a vector of compiled regular expressions. regex_t_sptrs_type& compiled_regex_fns_keep() { if (compiled_fns_keep_regexps_.empty()) { for (vector::const_iterator i = fns_keep_regexps_.begin(); i != fns_keep_regexps_.end(); ++i) { regex_t_sptr r = regex::compile(*i); if (r) compiled_fns_keep_regexps_.push_back(r); } } return compiled_fns_keep_regexps_; } /// Getter of the compiled regular expressions that designate the /// variables to suppress from the set of exported variables. /// /// @return a vector of compiled regular expressions. regex_t_sptrs_type& compiled_regex_vars_suppress() { if (compiled_vars_suppress_regexp_.empty()) { for (vector::const_iterator i = vars_suppress_regexps_.begin(); i != vars_suppress_regexps_.end(); ++i) { regex_t_sptr r = regex::compile(*i); if (r) compiled_vars_suppress_regexp_.push_back(r); } } return compiled_vars_suppress_regexp_; } /// Getter for the compiled regular expressions that designate the /// variables to keep in the set of exported variables. /// /// @return a vector of compiled regular expressions. regex_t_sptrs_type& compiled_regex_vars_keep() { if (compiled_vars_keep_regexps_.empty()) { for (vector::const_iterator i = vars_keep_regexps_.begin(); i != vars_keep_regexps_.end(); ++i) { regex_t_sptr r = regex::compile(*i); if (r) compiled_vars_keep_regexps_.push_back(r); } } return compiled_vars_keep_regexps_; } /// Getter for a map of the IDs of the functions that are present in /// the set of exported functions. /// /// This map is useful during the construction of the set of /// exported functions, at least to ensure that every function is /// present only once in that set. Actually, for each symbol ID, /// there can be several functions, given that each of those have /// different declaration names; this can happen with function /// template instantiations which decl names differ because the type /// parameters of the templates are typedefs of each other. /// /// @return a map which key is a string and which data is a pointer /// to a function. const str_fn_ptrs_map_type& id_fns_map() const {return id_fns_map_;} /// Getter for a map of the IDs of the functions that are present in /// the set of exported functions. /// /// This map is useful during the construction of the set of /// exported functions, at least to ensure that every function is /// present only once in that set. /// /// @return a map which key is a string and which data is a pointer /// to a function. str_fn_ptrs_map_type& id_fns_map() {return id_fns_map_;} /// Getter for a map of the IDs of the variables that are present in /// the set of exported variables. /// /// This map is useful during the construction of the set of /// exported variables, at least to ensure that every function is /// present only once in that set. /// /// @return a map which key is a string and which data is a pointer /// to a function. const str_var_ptr_map_type& id_var_map() const {return id_var_map_;} /// Getter for a map of the IDs of the variables that are present in /// the set of exported variables. /// /// This map is useful during the construction of the set of /// exported variables, at least to ensure that every function is /// present only once in that set. /// /// @return a map which key is a string and which data is a pointer /// to a function. str_var_ptr_map_type& id_var_map() {return id_var_map_;} /// Returns an ID for a given function. /// /// @param fn the function to calculate the ID for. /// /// @return a reference to a string representing the function ID. interned_string get_id(const function_decl& fn) {return fn.get_id();} /// Returns an ID for a given variable. /// /// @param var the variable to calculate the ID for. /// /// @return a reference to a string representing the variable ID. interned_string get_id(const var_decl& var) {return var.get_id();} /// Test if a given function ID is in the id-functions map. /// /// If it is, then return a pointer to the vector of functions with /// that ID. If not, just return nil. /// /// @param fn_id the ID to consider. /// /// @return the pointer to the vector of functions with ID @p fn_id, /// or nil if no function with that ID exists. vector* fn_id_is_in_id_fns_map(const string& fn_id) { str_fn_ptrs_map_type& m = id_fns_map(); str_fn_ptrs_map_type::iterator i = m.find(fn_id); if (i == m.end()) return 0; return &i->second; } /// Test if a a function if the same ID as a given function is /// present in the id-functions map. /// /// @param fn the function to consider. /// /// @return a pointer to the vector of functions with the same ID as /// @p fn, that are present in the id-functions map, or nil if no /// function with the same ID as @p fn is present in the /// id-functions map. vector* fn_id_is_in_id_fns_map(const function_decl* fn) { string fn_id = fn->get_id(); return fn_id_is_in_id_fns_map(fn_id); } /// Test if a given function is present in a vector of functions. /// /// The function compares the ID and the qualified name of /// functions. /// /// @param fn the function to consider. /// /// @parm fns the vector of functions to consider. static bool fn_is_in_fns(const function_decl* fn, const vector& fns) { if (fns.empty()) return false; const string fn_id = fn->get_id(); for (vector::const_iterator i = fns.begin(); i != fns.end(); ++i) if ((*i)->get_id() == fn_id && (*i)->get_qualified_name() == fn->get_qualified_name()) return true; return false; } /// Test if a function is in the id-functions map. /// /// @param fn the function to consider. /// /// @return true iff the function is in the id-functions map. bool fn_is_in_id_fns_map(const function_decl* fn) { vector* fns = fn_id_is_in_id_fns_map(fn); if (fns && fn_is_in_fns(fn, *fns)) return true; return false; } /// Add a given function to the map of functions that are present in /// the set of exported functions. /// /// @param fn the function to add to the map. void add_fn_to_id_fns_map(function_decl* fn) { if (!fn) return; // First associate the function id to the function. string fn_id = fn->get_id(); vector* fns = fn_id_is_in_id_fns_map(fn_id); if (!fns) fns = &(id_fns_map()[fn_id] = vector()); fns->push_back(fn); // Now associate all aliases of the underlying symbol to the // function too. elf_symbol_sptr sym = fn->get_symbol(); ABG_ASSERT(sym); string sym_id; do { sym_id = sym->get_id_string(); if (sym_id == fn_id) goto loop; fns = fn_id_is_in_id_fns_map(fn_id); if (!fns) fns = &(id_fns_map()[fn_id] = vector()); fns->push_back(fn); loop: sym = sym->get_next_alias(); } while (sym && !sym->is_main_symbol()); } /// Test if a given (ID of a) varialble is present in the variable /// map. In other words, it tests if a given variable is present in /// the set of exported variables. /// /// @param fn_id the ID of the variable to consider. /// /// @return true iff the variable designated by @p fn_id is present /// in the set of exported variables. bool var_id_is_in_id_var_map(const string& var_id) const { const str_var_ptr_map_type& m = id_var_map(); str_var_ptr_map_type::const_iterator i = m.find(var_id); return i != m.end(); } /// Add a given variable to the map of functions that are present in /// the set of exported functions. /// /// @param id the variable to add to the map. void add_var_to_map(var_decl* var) { if (var) { const string& var_id = get_id(*var); id_var_map()[var_id] = var; } } /// Add a function to the set of exported functions. /// /// @param fn the function to add to the set of exported functions. void add_fn_to_exported(const function_decl* fn) { if (!fn_is_in_id_fns_map(fn)) { fns_.push_back(const_cast(fn)); add_fn_to_id_fns_map(const_cast(fn)); } } /// Add a variable to the set of exported variables. /// /// @param fn the variable to add to the set of exported variables. void 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(const_cast(var)); add_var_to_map(const_cast(var)); } } /// Getter for the set of ids of functions to keep in the set of /// exported functions. /// /// @return the set of ids of functions to keep in the set of /// exported functions. const strings_type& sym_id_of_fns_to_keep() const {return sym_id_of_fns_to_keep_;} /// Getter for the set of ids of variables to keep in the set of /// exported variables. /// /// @return the set of ids of variables to keep in the set of /// exported variables. const strings_type& sym_id_of_vars_to_keep() const {return sym_id_of_vars_to_keep_;} /// Look at the set of functions to keep and tell if if a given /// function is to be kept, according to that set. /// /// @param fn the function to consider. /// /// @return true iff the function is to be kept. bool keep_wrt_id_of_fns_to_keep(const function_decl* fn) { if (!fn) return false; bool keep = true; if (elf_symbol_sptr sym = fn->get_symbol()) { if (!sym_id_of_fns_to_keep().empty()) keep = false; if (!keep) { for (vector::const_iterator i = sym_id_of_fns_to_keep().begin(); i != sym_id_of_fns_to_keep().end(); ++i) { string sym_name, sym_version; ABG_ASSERT(elf_symbol::get_name_and_version_from_id(*i, sym_name, sym_version)); if (sym_name == sym->get_name() && sym_version == sym->get_version().str()) { keep = true; break; } } } } else keep = false; return keep; } /// Look at the set of functions to suppress from the exported /// functions set and tell if if a given function is to be kept, /// according to that set. /// /// @param fn the function to consider. /// /// @return true iff the function is to be kept. bool keep_wrt_regex_of_fns_to_suppress(const function_decl *fn) { if (!fn) return false; string frep = fn->get_qualified_name(); bool keep = true; for (regex_t_sptrs_type::const_iterator i = compiled_regex_fns_suppress().begin(); i != compiled_regex_fns_suppress().end(); ++i) if (regex::match(*i, frep)) { keep = false; break; } return keep; } /// Look at the regular expressions of the functions to keep and /// tell if if a given function is to be kept, according to that /// set. /// /// @param fn the function to consider. /// /// @return true iff the function is to be kept. bool keep_wrt_regex_of_fns_to_keep(const function_decl *fn) { if (!fn) return false; string frep = fn->get_qualified_name(); bool keep = true; if (!compiled_regex_fns_keep().empty()) keep = false; if (!keep) for (regex_t_sptrs_type::const_iterator i = compiled_regex_fns_keep().begin(); i != compiled_regex_fns_keep().end(); ++i) if (regex::match(*i, frep)) { keep = true; break; } return keep; } /// Look at the regular expressions of the variables to keep and /// tell if if a given variable is to be kept, according to that /// set. /// /// @param fn the variable to consider. /// /// @return true iff the variable is to be kept. bool keep_wrt_id_of_vars_to_keep(const var_decl* var) { if (!var) return false; bool keep = true; if (elf_symbol_sptr sym = var->get_symbol()) { if (!sym_id_of_vars_to_keep().empty()) keep = false; if (!keep) { for (vector::const_iterator i = sym_id_of_vars_to_keep().begin(); i != sym_id_of_vars_to_keep().end(); ++i) { string sym_name, sym_version; ABG_ASSERT(elf_symbol::get_name_and_version_from_id(*i, sym_name, sym_version)); if (sym_name == sym->get_name() && sym_version == sym->get_version().str()) { keep = true; break; } } } } else keep = false; return keep; } /// Look at the set of variables to suppress from the exported /// variables set and tell if if a given variable is to be kept, /// according to that set. /// /// @param fn the variable to consider. /// /// @return true iff the variable is to be kept. bool keep_wrt_regex_of_vars_to_suppress(const var_decl *var) { if (!var) return false; string frep = var->get_qualified_name(); bool keep = true; for (regex_t_sptrs_type::const_iterator i = compiled_regex_vars_suppress().begin(); i != compiled_regex_vars_suppress().end(); ++i) if (regex::match(*i, frep)) { keep = false; break; } return keep; } /// Look at the regular expressions of the variables to keep and /// tell if if a given variable is to be kept, according to that /// set. /// /// @param fn the variable to consider. /// /// @return true iff the variable is to be kept. bool keep_wrt_regex_of_vars_to_keep(const var_decl *var) { if (!var) return false; string frep = var->get_qualified_name(); bool keep = true; if (!compiled_regex_vars_keep().empty()) keep = false; if (!keep) { for (regex_t_sptrs_type::const_iterator i = compiled_regex_vars_keep().begin(); i != compiled_regex_vars_keep().end(); ++i) if (regex::match(*i, frep)) { keep = true; break; } } return keep; } }; // end struct corpus::exported_decls_builder::priv /// The private data of the @ref corpus type. struct corpus::priv { mutable unordered_map canonical_types_; string format_major_version_number_; string format_minor_version_number_; const environment& env; corpus_group* group; corpus::exported_decls_builder_sptr exported_decls_builder; corpus::origin origin_; vector regex_patterns_fns_to_suppress; vector regex_patterns_vars_to_suppress; vector regex_patterns_fns_to_keep; vector regex_patterns_vars_to_keep; vector sym_id_fns_to_keep; vector sym_id_vars_to_keep; string path; vector needed; string soname; string architecture_name; translation_units members; string_tu_map_type path_tu_map; vector fns; vector vars; symtab_reader::symtab_sptr symtab_; // The type maps contained in this data member are populated if the // corpus follows the One Definition Rule and thus if there is only // one copy of a type with a given name, per corpus. Otherwise, if // there can be several *different* types with the same name, then // the type maps are all empty. The types are then maintained in // type maps that are in each translation units. // // In other words, to lookup a given type, if the corpus allows the // One Definition Rule, then lookup can be done by looking into this // data member. Otherwise, the lookup must be made by looking into // the type maps of each translation unit. type_maps types_; type_maps type_per_loc_map_; mutable vector types_not_reachable_from_pub_ifaces_; unordered_set *pub_type_pretty_reprs_; private: priv(); mutable abg_compat::optional sorted_var_symbols; mutable abg_compat::optional var_symbol_map; mutable abg_compat::optional sorted_undefined_var_symbols; mutable abg_compat::optional undefined_var_symbol_map; mutable abg_compat::optional unrefed_var_symbols; mutable abg_compat::optional sorted_fun_symbols; mutable abg_compat::optional fun_symbol_map; mutable abg_compat::optional sorted_undefined_fun_symbols; mutable abg_compat::optional undefined_fun_symbol_map; mutable abg_compat::optional unrefed_fun_symbols; public: priv(const string & p, const environment& e) : env(e), group(), origin_(ARTIFICIAL_ORIGIN), path(p), pub_type_pretty_reprs_() {} type_maps& get_types(); const type_maps& get_types() const; const elf_symbols& get_sorted_fun_symbols() const; const string_elf_symbols_map_type& get_fun_symbol_map() const; const elf_symbols& get_sorted_undefined_fun_symbols() const; const string_elf_symbols_map_type& get_undefined_fun_symbol_map() const; const elf_symbols& get_unreferenced_function_symbols() const; const elf_symbols& get_sorted_var_symbols() const; const string_elf_symbols_map_type& get_var_symbol_map() const; const elf_symbols& get_sorted_undefined_var_symbols() const; const string_elf_symbols_map_type& get_undefined_var_symbol_map() const; const elf_symbols& get_unreferenced_variable_symbols() const; unordered_set* get_public_types_pretty_representations(); ~priv(); }; // end struct corpus::priv void maybe_update_scope_lookup_map(const scope_decl_sptr& member_scope); void maybe_update_scope_lookup_map(const decl_base_sptr& member_scope); void maybe_update_types_lookup_map(const type_decl_sptr& basic_type); void maybe_update_types_lookup_map(const class_decl_sptr& class_type); void maybe_update_types_lookup_map(const union_decl_sptr& union_type); void maybe_update_types_lookup_map(const enum_type_decl_sptr& enum_type); void maybe_update_types_lookup_map(const typedef_decl_sptr& typedef_type); void maybe_update_types_lookup_map(const qualified_type_def_sptr& qualified_type); void maybe_update_types_lookup_map(const pointer_type_def_sptr& pointer_type); void maybe_update_types_lookup_map(const reference_type_def_sptr& reference_type); void maybe_update_types_lookup_map(const array_type_def_sptr& array_type); void maybe_update_types_lookup_map(scope_decl *scope, const function_type_sptr& function_type); void maybe_update_types_lookup_map(const decl_base_sptr& decl); void maybe_update_types_lookup_map(const type_base_sptr& type); }// end namespace ir }// end namespace abigail #endif // __ABG_CORPUS_PRIV_H__