// -*- Mode: C++ -*- // // Copyright (C) 2016-2019 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/>. // // Author: Dodji Seketeli #ifndef __ABG_SUPPRESSION_H__ #define __ABG_SUPPRESSION_H__ #include <tr1/unordered_set> #include "abg-ini.h" #include "abg-comparison.h" namespace abigail { /// @brief an engine to suppress the parts of the result of comparing /// two sets of ABI artifacts. /// /// The user specifies the kind of changes between ABI artefact she /// wants to see suppressed. That suppression specification is done /// in an INI format. /// /// That INI file is parsed and represented internally using the types /// that are defined in this namespace. namespace suppr { using namespace abigail::comparison; using std::tr1::unordered_set; /// Base type of the suppression specifications types. /// /// This abstracts a suppression specification. It's a way to specify /// how to drop reports about a particular diff node on the floor, if /// it matches the supppression specification. class suppression_base { class priv; typedef shared_ptr<priv> priv_sptr; // Forbid default constructor suppression_base(); public: priv_sptr priv_; suppression_base(const string& label); suppression_base(const string& label, const string& file_name_regex_str, const string& file_name_not_regex_str); bool get_drops_artifact_from_ir() const; void set_drops_artifact_from_ir(bool) const; bool get_is_artificial() const; void set_is_artificial(bool); const string get_label() const; void set_label(const string&); void set_file_name_regex_str(const string& regexp); const string& get_file_name_regex_str() const; void set_file_name_not_regex_str(const string& regexp); const string& get_file_name_not_regex_str() const; void set_soname_regex_str(const string& regexp); const string& get_soname_regex_str() const; void set_soname_not_regex_str(const string& regexp); const string& get_soname_not_regex_str() const; virtual bool suppresses_diff(const diff*) const = 0; virtual ~suppression_base(); }; // end class suppression_base void read_suppressions(std::istream& input, suppressions_type& suppressions); void read_suppressions(const string& file_path, suppressions_type& suppressions); class type_suppression; /// Convenience typedef for a shared pointer to type_suppression. typedef shared_ptr<type_suppression> type_suppression_sptr; /// Convenience typedef for vector of @ref type_suppression_sptr. typedef vector<type_suppression_sptr> type_suppressions_type; /// Abstraction of a type suppression specification. /// /// Specifies under which condition reports about a type diff node /// should be dropped on the floor. class type_suppression : public suppression_base { class priv; typedef shared_ptr<priv> priv_sptr; // Forbid this; type_suppression(); public: priv_sptr priv_; /// The kind of the type the current type suppression is supposed to /// be about. enum type_kind { UNKNOWN_TYPE_KIND, CLASS_TYPE_KIND, STRUCT_TYPE_KIND, UNION_TYPE_KIND, ENUM_TYPE_KIND, ARRAY_TYPE_KIND, TYPEDEF_TYPE_KIND, BUILTIN_TYPE_KIND }; // end enum type_kind /// The different ways through which the type diff has been reached. enum reach_kind { /// The type diff has been reached (from a function or variable /// change) directly. DIRECT_REACH_KIND = 0, /// The type diff has been reached (from a function or variable /// change) through a pointer. POINTER_REACH_KIND, /// The type diff has been reached (from a function or variable /// change) through a reference; you know, like a c++ reference.. REFERENCE_REACH_KIND, /// The type diff has been reached (from a function or variable /// change) through either a reference or a pointer. REFERENCE_OR_POINTER_REACH_KIND }; // end enum reach_kind class insertion_range; /// A convenience typedef for a shared pointer to @ref /// insertion_range. typedef shared_ptr<insertion_range> insertion_range_sptr; /// A convenience typedef for a vector of @ref insertion_range_sptr. typedef vector<insertion_range_sptr> insertion_ranges; type_suppression(const string& label, const string& type_name_regexp, const string& type_name); virtual ~type_suppression(); void set_type_name_regex_str(const string& name_regex_str); const string& get_type_name_regex_str() const; void set_type_name(const string& name); const string& get_type_name() const; bool get_consider_type_kind() const; void set_consider_type_kind(bool f); void set_type_kind(type_kind k); type_kind get_type_kind() const; bool get_consider_reach_kind() const; void set_consider_reach_kind(bool f); reach_kind get_reach_kind() const; void set_reach_kind(reach_kind k); void set_data_member_insertion_ranges(const insertion_ranges& r); const insertion_ranges& get_data_member_insertion_ranges() const; insertion_ranges& get_data_member_insertion_ranges(); const unordered_set<string>& get_source_locations_to_keep() const; unordered_set<string>& get_source_locations_to_keep(); void set_source_locations_to_keep(const unordered_set<string>&); const string& get_source_location_to_keep_regex_str() const; void set_source_location_to_keep_regex_str(const string&); const vector<string>& get_changed_enumerator_names() const; void set_changed_enumerator_names(const vector<string>&); virtual bool suppresses_diff(const diff* diff) const; bool suppresses_type(const type_base_sptr& type, const diff_context_sptr& ctxt) const; bool suppresses_type(const type_base_sptr& type) const; bool suppresses_type(const type_base_sptr& type, const scope_decl* type_scope) const; }; // end type_suppression type_suppression_sptr is_type_suppression(const suppression_sptr); /// The abstraction of a range of offsets in which a member of a type /// might get inserted. class type_suppression::insertion_range { public: class boundary; class integer_boundary; class fn_call_expr_boundary; /// Convenience typedef for a shared_ptr to @ref boundary typedef shared_ptr<boundary> boundary_sptr; /// Convenience typedef for a shared_ptr to a @ref integer_boundary typedef shared_ptr<integer_boundary> integer_boundary_sptr; /// Convenience typedef for a shared_ptr to a @ref /// fn_call_expr_boundary typedef shared_ptr<fn_call_expr_boundary> fn_call_expr_boundary_sptr; private: struct priv; typedef shared_ptr<priv> priv_sptr; priv_sptr priv_; public: insertion_range(); insertion_range(boundary_sptr begin, boundary_sptr end); boundary_sptr begin() const; boundary_sptr end() const; static insertion_range::integer_boundary_sptr create_integer_boundary(int value); static insertion_range::fn_call_expr_boundary_sptr create_fn_call_expr_boundary(ini::function_call_expr_sptr); static insertion_range::fn_call_expr_boundary_sptr create_fn_call_expr_boundary(const string&); static bool eval_boundary(boundary_sptr boundary, class_decl_sptr context, ssize_t& value); }; // end class insertion_range type_suppression::insertion_range::integer_boundary_sptr is_integer_boundary(type_suppression::insertion_range::boundary_sptr); type_suppression::insertion_range::fn_call_expr_boundary_sptr is_fn_call_expr_boundary(type_suppression::insertion_range::boundary_sptr); /// The abstraction of the boundary of an @ref insertion_range, in the /// context of a @ref type_suppression class type_suppression::insertion_range::boundary { struct priv; typedef shared_ptr<priv> priv_sptr; priv_sptr priv_; public: boundary(); virtual ~boundary(); };// end class type_suppression::insertion_range::boundary /// An @ref insertion_range boundary that is expressed as an integer /// value. That integer value is usually a bit offset. class type_suppression::insertion_range::integer_boundary : public type_suppression::insertion_range::boundary { struct priv; typedef shared_ptr<priv> priv_sptr; priv_sptr priv_; integer_boundary(); public: integer_boundary(int value); int as_integer() const; operator int() const; ~integer_boundary(); }; //end class type_suppression::insertion_range::integer_boundary /// An @ref insertion_range boundary that is expressed as function /// call expression. The (integer) value of that expression is /// usually a bit offset. class type_suppression::insertion_range::fn_call_expr_boundary : public type_suppression::insertion_range::boundary { struct priv; typedef shared_ptr<priv> priv_sptr; priv_sptr priv_; fn_call_expr_boundary(); public: fn_call_expr_boundary(ini::function_call_expr_sptr expr); ini::function_call_expr_sptr as_function_call_expr() const; operator ini::function_call_expr_sptr () const; ~fn_call_expr_boundary(); }; //end class type_suppression::insertion_range::fn_call_expr_boundary class function_suppression; /// Convenience typedef for a shared pointer to function_suppression. typedef shared_ptr<function_suppression> function_suppression_sptr; /// Convenience typedef for a vector of @ref function_suppression_sptr. typedef vector<function_suppression_sptr> function_suppressions_type; /// Abstraction of a function suppression specification. /// /// Specifies under which condition reports about a @ref /// function_decl_diff diff node should be dropped on the floor for /// the purpose of reporting. class function_suppression : public suppression_base { struct priv; typedef shared_ptr<priv> priv_sptr; public: priv_sptr priv_; class parameter_spec; /// Convenience typedef for shared_ptr of @ref parameter_spec. typedef shared_ptr<parameter_spec> parameter_spec_sptr; /// Convenience typedef for vector of @ref parameter_spec_sptr. typedef vector<parameter_spec_sptr> parameter_specs_type; /// The kind of change the current function suppression should apply /// to. enum change_kind { UNDEFINED_CHANGE_KIND, /// A change in a sub-type of the function. FUNCTION_SUBTYPE_CHANGE_KIND = 1, /// The function was added to the second subject of the diff. ADDED_FUNCTION_CHANGE_KIND = 1 << 1, /// The function was deleted from the second subject of the diff. DELETED_FUNCTION_CHANGE_KIND = 1 << 2, /// This represents all the changes possibly described by this /// enum. It's a logical 'OR' of all the change enumerators /// above. ALL_CHANGE_KIND = (FUNCTION_SUBTYPE_CHANGE_KIND | ADDED_FUNCTION_CHANGE_KIND | DELETED_FUNCTION_CHANGE_KIND) }; function_suppression(); function_suppression(const string& label, const string& name, const string& name_regex, const string& return_type_name, const string& return_type_regex, parameter_specs_type& parm_specs, const string& symbol_name, const string& symbol_name_regex, const string& symbol_version, const string& symbol_version_regex_str); virtual ~function_suppression(); static change_kind parse_change_kind(const string&); change_kind get_change_kind() const; void set_change_kind(change_kind k); const string& get_name() const; void set_name(const string&); const string& get_name_regex_str() const; void set_name_regex_str(const string&); const string& get_name_not_regex_str() const; void set_name_not_regex_str(const string&); const string& get_return_type_name() const; void set_return_type_name(const string&); const string& get_return_type_regex_str() const; void set_return_type_regex_str(const string& r); const parameter_specs_type& get_parameter_specs() const; void set_parameter_specs(parameter_specs_type&); void append_parameter_specs(const parameter_spec_sptr); const string& get_symbol_name() const; void set_symbol_name(const string& n); const string& get_symbol_name_regex_str() const; void set_symbol_name_regex_str(const string&); const string& get_symbol_version() const; void set_symbol_version(const string&); const string& get_symbol_version_regex_str() const; void set_symbol_version_regex_str(const string&); bool get_allow_other_aliases() const; void set_allow_other_aliases(bool f); virtual bool suppresses_diff(const diff* diff) const; bool suppresses_function(const function_decl* fn, change_kind k, const diff_context_sptr ctxt) const; bool suppresses_function(const function_decl_sptr fn, change_kind k, const diff_context_sptr ctxt) const; bool suppresses_function_symbol(const elf_symbol* sym, change_kind k, const diff_context_sptr ctxt); bool suppresses_function_symbol(const elf_symbol_sptr sym, change_kind k, const diff_context_sptr ctxt); }; // end class function_suppression. function_suppression_sptr is_function_suppression(const suppression_sptr); function_suppression::change_kind operator&(function_suppression::change_kind l, function_suppression::change_kind r); function_suppression::change_kind operator|(function_suppression::change_kind l, function_suppression::change_kind r); /// Abstraction of the specification of a function parameter in a /// function suppression specification. class function_suppression::parameter_spec { class priv; typedef shared_ptr<priv> priv_sptr; friend class function_suppression; priv_sptr priv_; // Forbid this. parameter_spec(); public: parameter_spec(size_t index, const string& type_name, const string& type_name_regex); size_t get_index() const; void set_index(size_t); const string& get_parameter_type_name() const; void set_parameter_type_name(const string&); const string& get_parameter_type_name_regex_str() const; void set_parameter_type_name_regex_str(const string&); };// end class function_suppression::parameter_spec class variable_suppression; /// A convenience typedef for a shared pointer to @ref /// variable_suppression. typedef shared_ptr<variable_suppression> variable_suppression_sptr; /// A convenience typedef for a vector of @ref /// variable_suppression_sptr. typedef vector<variable_suppression_sptr> variable_suppressions_type; /// The abstraction of a variable suppression specification. /// /// It specifies under which condition reports about a @ref var_diff /// diff node should be dropped on the floor for the purpose of /// reporting. class variable_suppression : public suppression_base { public: /// The kind of change the current variable suppression should apply /// to. enum change_kind { UNDEFINED_CHANGE_KIND, /// A change in a sub-type of the variable. VARIABLE_SUBTYPE_CHANGE_KIND = 1, /// The variable was added to the second second subject of the /// diff. ADDED_VARIABLE_CHANGE_KIND = 1 << 1, /// The variable was deleted from the second subject of the diff. DELETED_VARIABLE_CHANGE_KIND = 1 << 2, /// This represents all the changes possibly described by this /// enum. It's a logical 'OR' of all the change enumerators /// above. ALL_CHANGE_KIND = (VARIABLE_SUBTYPE_CHANGE_KIND | ADDED_VARIABLE_CHANGE_KIND | DELETED_VARIABLE_CHANGE_KIND) }; private: struct priv; typedef shared_ptr<priv> priv_sptr; public: priv_sptr priv_; variable_suppression(const string& label = "", const string& name = "", const string& name_regex_str = "", const string& symbol_name = "", const string& symbol_name_regex_str = "", const string& symbol_version = "", const string& symbol_version_regex_str = "", const string& type_name = "", const string& type_name_regex_str = ""); virtual ~variable_suppression(); static change_kind parse_change_kind(const string&); change_kind get_change_kind() const; void set_change_kind(change_kind k); const string& get_name() const; void set_name(const string&); const string& get_name_regex_str() const; void set_name_regex_str(const string&); const string& get_name_not_regex_str() const; void set_name_not_regex_str(const string&); const string& get_symbol_name() const; void set_symbol_name(const string&); const string& get_symbol_name_regex_str() const; void set_symbol_name_regex_str(const string&); const string& get_symbol_version() const; void set_symbol_version(const string&); const string& get_symbol_version_regex_str() const; void set_symbol_version_regex_str(const string&); const string& get_type_name() const; void set_type_name(const string&); const string& get_type_name_regex_str() const; void set_type_name_regex_str(const string&); bool suppresses_diff(const diff* d) const; bool suppresses_variable(const var_decl* var, change_kind k, const diff_context_sptr cxt) const; bool suppresses_variable(const var_decl_sptr var, change_kind k, const diff_context_sptr cxt) const; bool suppresses_variable_symbol(const elf_symbol* sym, change_kind k, const diff_context_sptr cxt) const; bool suppresses_variable_symbol(const elf_symbol_sptr fn, change_kind k, const diff_context_sptr cxt) const; }; // end class variable_suppression variable_suppression_sptr is_variable_suppression(const suppression_sptr); variable_suppression::change_kind operator&(variable_suppression::change_kind l, variable_suppression::change_kind r); variable_suppression::change_kind operator|(variable_suppression::change_kind l, variable_suppression::change_kind r); class file_suppression; /// A convenience typedef for a shared_ptr to @ref file_suppression typedef shared_ptr<file_suppression> file_suppression_sptr; /// Abstraction of a suppression specification to avoid loading a /// file. /// /// This can be used by a tool that loads (binary) files, to know /// which file it has to avoid loading. class file_suppression: public suppression_base { class priv; typedef shared_ptr<priv> priv_sptr; priv_sptr priv_; // Forbid this file_suppression(); public: file_suppression(const string& label, const string& file_name_regex, const string& file_name_not_regex); virtual bool suppresses_diff(const diff* diff) const; bool suppresses_file(const string& file_path); virtual ~file_suppression(); }; // end file_suppression file_suppression_sptr is_file_suppression(const suppression_sptr); file_suppression_sptr file_is_suppressed(const string& file_path, const suppressions_type& suppressions); const char* get_private_types_suppr_spec_label(); bool is_private_type_suppr_spec(const type_suppression&); bool is_private_type_suppr_spec(const suppression_sptr& s); } // end namespace suppr } // end namespace abigail #endif //__ABG_SUPPRESSION_H__