From: Dodji Seketeli Date: Fri, 18 Oct 2019 08:13:41 +0000 (+0200) Subject: Support symbol_name_not_regexp in [suppress_{function, variable}] X-Git-Tag: upstream/1.7~41 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b00976517fb3f622e7a6e44204b3f1161e9e2952;p=platform%2Fupstream%2Flibabigail.git Support symbol_name_not_regexp in [suppress_{function, variable}] In the suppress_function and suppress_variable directives of the suppression specification language, we lack the 'symbol_name_not_regexp' properties, that would allow users to specify which (function/variable) symbols to *keep* as opposed to specifying which symbols to suppress. This patch adds that feature. That will later allow us to make the linux kernel symbol white lists[1] functionality use this feature; that is, upon analysing the content of a kernel symbol whitelist which lists a symbol named "foo", Libabigail would automatically generate a suppression specification which contains, e.g a 'suppress_function" directive that has this new 'symbol_name_not_regexp' property which value is set to "foo". Note that the patch makes sure that feature is supported when analyzing both abixml and DWARF formats. [1]: You can learn about what a Linux Kernel symbols white list is by reading about it at https://sourceware.org/libabigail/manual/kmidiff.html#environment. * doc/manuals/libabigail-concepts.rst: Document the new symbol_name_not_regexp properties for the suppress_{function,variable} directives. * include/abg-suppression.h ({function,variable}_suppression::{g,s}et_symbol_name_not_regex_str): Declare new member functions. * src/abg-dwarf-reader.cc (read_context::is_elf_symbol_suppressed): Define new member functions. (read_context::{load_symbol_maps_from_symtab_section, populate_symbol_map_from_ksymtab, populate_symbol_map_from_ksymtab_reloc}): Drop suppressed symbols when reading symbol tables. ({function,variable}_is_suppressed): Consider that in C, the linkage name is _by default_ the same as the function/variable name. Remove local variable. * include/abg-ir.h (elf_symbol_is_{function,variable}): Add ... * src/abg-ir.cc (elf_symbol_is_{function,variable}): ... new functions. * src/abg-reader.cc (build_elf_symbol): Take an additional boolean to detect and drop suppressed symbols. (build_elf_symbol_db): Adjust the call to build_elf_symbol to make it detect and drop suppressed symbols. (read_corpus_from_input): Be mindful that the set of symbols for a given corpus can be empty because of suppression specifications. * src/abg-suppression-priv.h ({function,variable}_suppression::priv::symbol_name_not_regex[_str_]): Add new data members. (function,variable}_suppression::priv::get_symbol_name_not_regex): Add new member functions. ({function,variable}_is_suppressed): Guard against empty name. (is_elf_symbol_suppressed): Define new function template. * src/abg-suppression.cc ({function,variable}_suppression::{g,s}et_symbol_name_not_regex_str): Define new member functions. ({function,variable}_suppression::suppresses_function) (suppression_matches_{function,variable}_sym_name) (read_{function,variable}_suppression): Support the new "symbol_name_not_regex" property. * tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-1.txt: New test reference report. * tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-2.txt: Likewise. * tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v{0,1}.c: Sources of the new test input. * tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v{0,1}.o: New test input binaries. * tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v{0,1}.o.abi: New test input abixml files. * tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp.suppr.txt: Next test suppression specification. * tests/data/Makefile.am: Add the new test material above to source distribution. * tests/test-diff-suppr.cc (in_out_specs): Add the input tests above to the test harness. Signed-off-by: Dodji Seketeli --- diff --git a/doc/manuals/libabigail-concepts.rst b/doc/manuals/libabigail-concepts.rst index a1835d19..6565d30b 100644 --- a/doc/manuals/libabigail-concepts.rst +++ b/doc/manuals/libabigail-concepts.rst @@ -601,7 +601,8 @@ one of the following properties must be provided: ``label``, ``file_name_regexp``, ``file_name_not_regexp``, ``soname_regexp``, ``soname_not_regexp``, ``name``, ``name_regexp``, ``name_not_regexp``, ``parameter``, ``return_type_name``, - ``symbol_name``, ``symbol_name_regexp``, ``symbol_version``, + ``symbol_name``, ``symbol_name_regexp``, + ``symbol_name_not_regexp``,``symbol_version``, ``symbol_version_regexp``. If none of the following properties are provided, then the @@ -830,6 +831,15 @@ The potential properties of this sections are: the aliases of the function for the directive to actually suppress the diff reports for said function. +* ``symbol_name_not_regexp`` + + Usage: + + ``symbol_name_not_regexp`` ``=`` <:ref:`regular-expression `> + + Suppresses change reports involving functions whose symbol name does + not match the regular expression specified as value of this property. + * ``symbol_version`` Usage: @@ -879,8 +889,8 @@ one of the following properties must be provided: ``label``, ``file_name_regexp``, ``file_name_not_regexp``, ``soname_regexp``, ``soname_not_regexp``, ``name``, ``name_regexp``, - ``symbol_name``, ``symbol_name_regexp``, ``symbol_version``, - ``symbol_version_regexp``. + ``symbol_name``, ``symbol_name_regexp``, ``symbol_name_not_regexp``, + ``symbol_version``, ``symbol_version_regexp``. If none of the following properties are provided, then the ``[suppres_variable]`` directive is simply ignored. @@ -988,6 +998,15 @@ The potential properties of this sections are: matches the regular expression specified as value of this property. +* ``symbol_name_not_regexp`` + + Usage: + + ``symbol_name_not_regexp`` ``=`` <:ref:`regular-expression `> + + Suppresses change reports involving variables whose symbol name does + not match the regular expression specified as value of this property. + * ``symbol_version`` Usage: diff --git a/include/abg-ir.h b/include/abg-ir.h index 0d344f79..43455714 100644 --- a/include/abg-ir.h +++ b/include/abg-ir.h @@ -992,6 +992,12 @@ string_to_elf_symbol_binding(const string&, elf_symbol::binding&); bool string_to_elf_symbol_visibility(const string&, elf_symbol::visibility&); +bool +elf_symbol_is_function(elf_symbol::type); + +bool +elf_symbol_is_variable(elf_symbol::type); + bool operator==(const elf_symbol_sptr& lhs, const elf_symbol_sptr& rhs); diff --git a/include/abg-suppression.h b/include/abg-suppression.h index 47dac5a9..02f3fc4c 100644 --- a/include/abg-suppression.h +++ b/include/abg-suppression.h @@ -518,6 +518,12 @@ public: void set_symbol_name_regex_str(const string&); + const string& + get_symbol_name_not_regex_str() const; + + void + set_symbol_name_not_regex_str(const string&); + const string& get_symbol_version() const; @@ -707,6 +713,12 @@ public: void set_symbol_name_regex_str(const string&); + const string& + get_symbol_name_not_regex_str() const; + + void + set_symbol_name_not_regex_str(const string&); + const string& get_symbol_version() const; diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc index f2ebede1..1ae0ed70 100644 --- a/src/abg-dwarf-reader.cc +++ b/src/abg-dwarf-reader.cc @@ -7385,6 +7385,10 @@ public: ABG_ASSERT(symbol); ABG_ASSERT(symbol->is_function()); + // If the symbol was suppressed by a suppression + // specification then drop it on the floor. + if (is_elf_symbol_suppressed(symbol)) + continue; if (load_fun_map && symbol->is_public()) { @@ -7850,6 +7854,21 @@ public: return nb_ksymtab_gpl_entries_; } + /// Test if a given ELF symbol was suppressed by a suppression + /// specification. + /// + /// @param symbol the ELF symbol to consider. + /// + /// @return true iff @p symbol is suppressed. + bool + is_elf_symbol_suppressed(const elf_symbol_sptr& symbol) const + { + return (symbol + && suppr::is_elf_symbol_suppressed(*this, + symbol->get_name(), + symbol->get_type())); + } + /// Populate the symbol map by reading exported symbols from the /// ksymtab directly. /// @@ -7939,6 +7958,11 @@ public: continue; } + // If the symbol was suppressed by a suppression + // specification then drop it on the floor. + if (is_elf_symbol_suppressed(symbol)) + continue; + address_set_sptr set; if (symbol->is_function()) { @@ -8031,6 +8055,11 @@ public: continue; } + // If the symbol was suppressed by a suppression + // specification then drop it on the floor. + if (is_elf_symbol_suppressed(symbol)) + continue; + // If we are looking at an ET_REL (relocatable) binary, then // the symbol value of native_symbol is relative to the // section that symbol is defined in. We need to translate it @@ -16477,13 +16506,14 @@ function_is_suppressed(const read_context& ctxt, string fname = die_string_attribute(function_die, DW_AT_name); string flinkage_name = die_linkage_name(function_die); + if (flinkage_name.empty() && ctxt.die_is_in_c(function_die)) + flinkage_name = fname; string qualified_name = build_qualified_name(scope, fname); // A non-member function which symbol is not exported is suppressed. if (!is_class_type(scope) && !die_is_declaration_only(function_die)) { Dwarf_Addr fn_addr; - elf_symbol_sptr fn_sym; if (!ctxt.get_function_address(function_die, fn_addr)) return true; if (!get_ignore_symbol_table(ctxt)) @@ -16583,6 +16613,8 @@ variable_is_suppressed(const read_context& ctxt, string name = die_string_attribute(variable_die, DW_AT_name); string linkage_name = die_linkage_name(variable_die); + if (linkage_name.empty() && ctxt.die_is_in_c(variable_die)) + linkage_name = name; string qualified_name = build_qualified_name(scope, name); // If a non member variable that is a declaration (has no exported @@ -16597,7 +16629,6 @@ variable_is_suppressed(const read_context& ctxt, if (!is_class_type(scope) && !is_required_decl_spec) { Dwarf_Addr var_addr = 0; - elf_symbol_sptr var_sym; if (!ctxt.get_variable_address(variable_die, var_addr)) return true; if (!get_ignore_symbol_table(ctxt)) diff --git a/src/abg-ir.cc b/src/abg-ir.cc index 87b20e48..ebe2e3fa 100644 --- a/src/abg-ir.cc +++ b/src/abg-ir.cc @@ -2314,6 +2314,26 @@ string_to_elf_symbol_visibility(const string& s, elf_symbol::visibility& v) return true; } +/// Test if the type of an ELF symbol denotes a function symbol. +/// +/// @param t the type of the ELF symbol. +/// +/// @return true iff elf symbol type @p t denotes a function symbol +/// type. +bool +elf_symbol_is_function(elf_symbol::type t) +{return t == elf_symbol::FUNC_TYPE;} + +/// Test if the type of an ELF symbol denotes a function symbol. +/// +/// @param t the type of the ELF symbol. +/// +/// @return true iff elf symbol type @p t denotes a function symbol +/// type. +bool +elf_symbol_is_variable(elf_symbol::type t) +{return t == elf_symbol::OBJECT_TYPE;} + // struct elf_symbol::version::priv diff --git a/src/abg-reader.cc b/src/abg-reader.cc index 2ff6dfce..ce1f3ea7 100644 --- a/src/abg-reader.cc +++ b/src/abg-reader.cc @@ -1093,7 +1093,7 @@ build_namespace_decl(read_context&, const xmlNodePtr, bool); // below. static elf_symbol_sptr -build_elf_symbol(read_context&, const xmlNodePtr); +build_elf_symbol(read_context&, const xmlNodePtr, bool); static elf_symbol_sptr build_elf_symbol_from_reference(read_context&, const xmlNodePtr, @@ -1882,7 +1882,9 @@ read_corpus_from_input(read_context& ctxt) bool is_ok = read_symbol_db_from_input(ctxt, fn_sym_db, var_sym_db); if (is_ok) { - ABG_ASSERT(fn_sym_db || var_sym_db); + // Note that it's possible that both fn_sym_db and var_sym_db + // are nil, due to potential suppression specifications. That's + // fine. if (fn_sym_db) { corp.set_fun_symbol_map(fn_sym_db); @@ -2592,9 +2594,13 @@ build_namespace_decl(read_context& ctxt, /// /// @param node the XML node to read. /// +/// @param drop_if_suppressed if the elf symbol was suppressed by a +/// suppression specification then do not build it. +/// /// @return the @ref elf_symbol built, or nil if it couldn't be built. static elf_symbol_sptr -build_elf_symbol(read_context& ctxt, const xmlNodePtr node) +build_elf_symbol(read_context& ctxt, const xmlNodePtr node, + bool drop_if_suppressed) { elf_symbol_sptr nil; @@ -2657,6 +2663,9 @@ build_elf_symbol(read_context& ctxt, const xmlNodePtr node) elf_symbol::version version(version_string, is_default_version); + if (drop_if_suppressed && suppr::is_elf_symbol_suppressed(ctxt, name, type)) + return elf_symbol_sptr(); + const environment* env = ctxt.get_environment(); elf_symbol_sptr e = elf_symbol::create(env, /*index=*/0, size, name, type, binding, @@ -2758,7 +2767,7 @@ build_elf_symbol_db(read_context& ctxt, elf_symbol_sptr sym; for (xmlNodePtr n = node->children; n; n = n->next) { - if ((sym = build_elf_symbol(ctxt, n))) + if ((sym = build_elf_symbol(ctxt, n, /*drop_if_suppress=*/true))) { id_sym_map[sym->get_id_string()] = sym; xml_node_ptr_elf_symbol_map[n] = sym; diff --git a/src/abg-suppression-priv.h b/src/abg-suppression-priv.h index 07e17180..449814c9 100644 --- a/src/abg-suppression-priv.h +++ b/src/abg-suppression-priv.h @@ -272,6 +272,8 @@ struct function_suppression::priv string symbol_name_; string symbol_name_regex_str_; mutable sptr_utils::regex_t_sptr symbol_name_regex_; + string symbol_name_not_regex_str_; + mutable sptr_utils::regex_t_sptr symbol_name_not_regex_; string symbol_version_; string symbol_version_regex_str_; mutable sptr_utils::regex_t_sptr symbol_version_regex_; @@ -397,6 +399,29 @@ struct function_suppression::priv return symbol_name_regex_; } + /// Getter for a pointer to a regular expression object built from + /// the regular expression string + /// function_suppression::priv::symbol_name_not_regex_str_. + /// + /// If that string is empty, then an empty regular expression object + /// pointer is returned. + /// + /// @return a pointer to the regular expression object of + /// function_suppression::priv::symbol_name_not_regex_str_. + const sptr_utils::regex_t_sptr + get_symbol_name_not_regex() const + { + if (!symbol_name_not_regex_ && !symbol_name_not_regex_str_.empty()) + { + sptr_utils::regex_t_sptr r = sptr_utils::build_sptr(); + if (regcomp(r.get(), + symbol_name_not_regex_str_.c_str(), + REG_EXTENDED) == 0) + symbol_name_not_regex_ = r; + } + return symbol_name_not_regex_; + } + /// Getter for a pointer to a regular expression object built from /// the regular expression string /// function_suppression::priv::symbol_version_regex_str_. @@ -474,10 +499,12 @@ function_is_suppressed(const ReadContextType& ctxt, { if (require_drop_property && !(*i)->get_drops_artifact_from_ir()) continue; - if (ctxt.suppression_matches_function_name(*suppr, fn_name)) + if (!fn_name.empty() + && ctxt.suppression_matches_function_name(*suppr, fn_name)) return true; - if (ctxt.suppression_matches_function_sym_name(*suppr, - fn_linkage_name)) + if (!fn_linkage_name.empty() + && ctxt.suppression_matches_function_sym_name(*suppr, + fn_linkage_name)) return true; } return false; @@ -500,6 +527,8 @@ struct variable_suppression::priv string symbol_name_; string symbol_name_regex_str_; mutable sptr_utils::regex_t_sptr symbol_name_regex_; + string symbol_name_not_regex_str_; + mutable sptr_utils::regex_t_sptr symbol_name_not_regex_; string symbol_version_; string symbol_version_regex_str_; mutable sptr_utils::regex_t_sptr symbol_version_regex_; @@ -595,6 +624,28 @@ struct variable_suppression::priv return symbol_name_regex_; } + /// Getter for a pointer to a regular expression object built from + /// the regular expression string + /// variable_suppression::priv::symbol_name_not_regex_str_. + /// + /// If that string is empty, then an empty regular expression object + /// pointer is returned. + /// + /// @return a pointer to the regular expression object of + /// variable_suppression::priv::symbol_name_not_regex_str_. + const sptr_utils::regex_t_sptr + get_symbol_name_not_regex() const + { + if (!symbol_name_not_regex_ && !symbol_name_not_regex_str_.empty()) + { + sptr_utils::regex_t_sptr r = sptr_utils::build_sptr(); + if (regcomp(r.get(), symbol_name_not_regex_str_.c_str(), + REG_EXTENDED == 0) == 0) + symbol_name_not_regex_ = r; + } + return symbol_name_not_regex_; + } + /// Getter for a pointer to a regular expression object built from /// the regular expression string /// variable_suppression::priv::symbol_version_regex_str_. @@ -657,10 +708,12 @@ variable_is_suppressed(const ReadContextType& ctxt, { if (require_drop_property && !(*i)->get_drops_artifact_from_ir()) continue; - if (ctxt.suppression_matches_variable_name(*suppr, var_name)) + if (!var_name.empty() + && ctxt.suppression_matches_variable_name(*suppr, var_name)) return true; - if (ctxt.suppression_matches_variable_sym_name(*suppr, - var_linkage_name)) + if (!var_linkage_name.empty() + && ctxt.suppression_matches_variable_sym_name(*suppr, + var_linkage_name)) return true; } return false; @@ -915,6 +968,33 @@ type_is_suppressed(const ReadContextType& ctxt, return false; } +/// Test if a given ELF symbol is suppressed by a suppression +/// specification. +/// +/// @param ctxt the read context to use. +/// +/// @param sym_name the name of the symbol to consider. +/// +/// @param sym_type the type of the symbol to consider. +/// +/// @return true iff the elf symbol denoted by @p sym_name and @p +/// sym_type is suppressed. +template +bool +is_elf_symbol_suppressed(const ReadContextType& ctxt, + const string& sym_name, + elf_symbol::type sym_type) +{ + if (elf_symbol_is_function(sym_type)) + return suppr::function_is_suppressed(ctxt, /*fn_name=*/"", + /*symbol_name=*/sym_name); + else if (elf_symbol_is_variable(sym_type)) + return suppr::variable_is_suppressed(ctxt, /*var_name=*/"", + /*symbol_name=*/sym_name); + + return false; +} + // }// end namespace suppr diff --git a/src/abg-suppression.cc b/src/abg-suppression.cc index 1c10c8e6..05d38581 100644 --- a/src/abg-suppression.cc +++ b/src/abg-suppression.cc @@ -2265,6 +2265,45 @@ void function_suppression::set_symbol_name_regex_str(const string& r) {priv_->symbol_name_regex_str_ = r;} +/// Getter for a regular expression for a family of names of symbols +/// of functions the user wants this specification to designate. +/// +/// If a symbol name is matched by this regular expression, then the +/// suppression specification will *NOT* suppress the symbol. +/// +/// If the symbol name as returned by +/// function_suppression::get_symbol_name() is not empty, then this +/// property is ignored at specification evaluation time. +/// +/// This property might be empty, in which case it's ignored at +/// evaluation time. +/// +/// @return the regular expression string for a family of names of +/// symbols that is to be *NOT* suppressed by this suppression specification. +const string& +function_suppression::get_symbol_name_not_regex_str() const +{return priv_->symbol_name_not_regex_str_;} + +/// Setter for a regular expression for a family of names of symbols +/// of functions the user wants this specification to designate. +/// +/// If a symbol name is matched by this regular expression, then the +/// suppression specification will *NOT* suppress the symbol. +/// +/// If the symbol name as returned by +/// function_suppression::get_symbol_name() is not empty, then this +/// property is ignored at specification evaluation time. +/// +/// This property might be empty, in which case it's ignored at +/// evaluation time. +/// +/// @param the new regular expression string for a family of names of +/// symbols that is to be *NOT* suppressed by this suppression +/// specification. +void +function_suppression::set_symbol_name_not_regex_str(const string& r) +{priv_->symbol_name_not_regex_str_ = r;} + /// Getter for the name of the version of the symbol of the function /// the user wants this specification to designate. /// @@ -2522,8 +2561,8 @@ function_suppression::suppresses_function(const function_decl* fn, return false; } - // Check if the "symbol_name" and "symbol_name_regexp" properties - // match. + // Check if the "symbol_name", "symbol_name_regexp", and + // "symbol_name_not_regexp" properties match. string fn_sym_name, fn_sym_version; elf_symbol_sptr sym = fn->get_symbol(); if (sym) @@ -2562,6 +2601,14 @@ function_suppression::suppresses_function(const function_decl* fn, 0, NULL, 0) != 0)) return false; + const sptr_utils::regex_t_sptr symbol_name_not_regex = + priv_->get_symbol_name_not_regex(); + if (symbol_name_not_regex + && (regexec(symbol_name_not_regex.get(), + fn_sym_name.c_str(), + 0, NULL, 0) == 0)) + return false; + if (get_allow_other_aliases()) { // In this case, we want to allow the suppression of change @@ -2572,11 +2619,19 @@ function_suppression::suppresses_function(const function_decl* fn, for (elf_symbol_sptr a = sym->get_next_alias(); a && !a->is_main_symbol(); a = a->get_next_alias()) - if (symbol_name_regex - && (regexec(symbol_name_regex.get(), - a->get_name().c_str(), - 0, NULL, 0) != 0)) - return false; + { + if (symbol_name_regex + && (regexec(symbol_name_regex.get(), + a->get_name().c_str(), + 0, NULL, 0) != 0)) + return false; + + if (symbol_name_not_regex + && (regexec(symbol_name_not_regex.get(), + a->get_name().c_str(), + 0, NULL, 0) == 0)) + return false; + } } } } @@ -2875,6 +2930,11 @@ suppression_matches_function_sym_name(const suppr::function_suppression& s, if (regexec(regexp.get(), fn_linkage_name.c_str(), 0, NULL, 0) != 0) return false; } + else if (sptr_utils::regex_t_sptr regexp = s.priv_->get_symbol_name_not_regex()) + { + if (regexec(regexp.get(), fn_linkage_name.c_str(), 0, NULL, 0) == 0) + return false; + } else if (s.priv_->symbol_name_.empty()) return false; else // if (!s.priv_->symbol_name_.empty()) @@ -2937,6 +2997,12 @@ suppression_matches_variable_sym_name(const suppr::variable_suppression& s, if (regexec(regexp.get(), var_linkage_name.c_str(), 0, NULL, 0) != 0) return false; } + else if (sptr_utils::regex_t_sptr regexp = + s.priv_->get_symbol_name_not_regex()) + { + if (regexec(regexp.get(), var_linkage_name.c_str(), 0, NULL, 0) == 0) + return false; + } else if (s.priv_->symbol_name_.empty()) return false; else // if (!s.priv_->symbol_name_.empty()) @@ -3149,6 +3215,12 @@ read_function_suppression(const ini::config::section& section) ? sym_name_regex_prop->get_value()->as_string() : ""; + ini::simple_property_sptr sym_name_not_regex_prop = + is_simple_property(section.find_property("symbol_name_not_regexp")); + string sym_name_not_regex_str = sym_name_not_regex_prop + ? sym_name_not_regex_prop->get_value()->as_string() + : ""; + ini::simple_property_sptr sym_ver_prop = is_simple_property(section.find_property("symbol_version")); string sym_version = sym_ver_prop @@ -3195,6 +3267,7 @@ read_function_suppression(const ini::config::section& section) || !return_type_regex_str.empty() || !sym_name.empty() || !sym_name_regex_str.empty() + || !sym_name_not_regex_str.empty() || !sym_version.empty() || !sym_ver_regex_str.empty() || !parms.empty()) @@ -3213,7 +3286,8 @@ read_function_suppression(const ini::config::section& section) || !name_regex_str.empty() || !name_not_regex_str.empty() || !sym_name.empty() - || !sym_name_regex_str.empty())) + || !sym_name_regex_str.empty() + || !sym_name_not_regex_str.empty())) result->set_drops_artifact_from_ir(true); if (result && !change_kind_str.empty()) @@ -3227,6 +3301,9 @@ read_function_suppression(const ini::config::section& section) if (!name_not_regex_str.empty()) result->set_name_not_regex_str(name_not_regex_str); + if (!sym_name_not_regex_str.empty()) + result->set_symbol_name_not_regex_str(sym_name_not_regex_str); + if (!file_name_regex_str.empty()) result->set_file_name_regex_str(file_name_regex_str); @@ -3458,6 +3535,45 @@ void variable_suppression::set_symbol_name_regex_str(const string& r) {priv_->symbol_name_regex_str_ = r;} +/// Getter for a regular expression for a family of names of symbols +/// of variables the user wants this specification to designate. +/// +/// If a symbol name is matched by this regular expression, then the +/// suppression specification will *NOT* suppress the symbol. +/// +/// If the symbol name as returned by +/// variable_suppression::get_symbol_name() is not empty, then this +/// property is ignored at specification evaluation time. +/// +/// This property might be empty, in which case it's ignored at +/// evaluation time. +/// +/// @return the regular expression string for a family of names of +/// symbols that is to be *NOT* suppressed by this suppression specification. +const string& +variable_suppression::get_symbol_name_not_regex_str() const +{return priv_->symbol_name_not_regex_str_;} + +/// Setter for a regular expression for a family of names of symbols +/// of variables the user wants this specification to designate. +/// +/// If a symbol name is matched by this regular expression, then the +/// suppression specification will *NOT* suppress the symbol. +/// +/// If the symbol name as returned by +/// variable_suppression::get_symbol_name() is not empty, then this +/// property is ignored at specification evaluation time. +/// +/// This property might be empty, in which case it's ignored at +/// evaluation time. +/// +/// @param the new regular expression string for a family of names of +/// symbols that is to be *NOT* suppressed by this suppression +/// specification. +void +variable_suppression::set_symbol_name_not_regex_str(const string& r) +{priv_->symbol_name_not_regex_str_ = r;} + /// Getter for the version of the symbol of the variable the user /// wants the current specification to designate. This property might /// be empty, in which case it's ignored at evaluation time. @@ -3637,7 +3753,8 @@ variable_suppression::suppresses_variable(const var_decl* var, } } - // Check for the symbol_name property match. + // Check for the symbol_name, symbol_name_regex and + // symbol_name_not_regex property match. string var_sym_name = var->get_symbol() ? var->get_symbol()->get_name() : ""; if (!get_symbol_name().empty()) { @@ -3652,6 +3769,13 @@ variable_suppression::suppresses_variable(const var_decl* var, && (regexec(sym_name_regex.get(), var_sym_name.c_str(), 0, NULL, 0) != 0)) return false; + + const sptr_utils::regex_t_sptr sym_name_not_regex = + priv_->get_symbol_name_not_regex(); + if (sym_name_not_regex + && (regexec(sym_name_not_regex.get(), var_sym_name.c_str(), + 0, NULL, 0) == 0)) + return false; } // Check for symbol_version and symbol_version_regexp property match @@ -3965,6 +4089,12 @@ read_variable_suppression(const ini::config::section& section) ? sym_name_regex_prop->get_value()->as_string() : ""; + ini::simple_property_sptr sym_name_not_regex_prop = + is_simple_property(section.find_property("symbol_name_not_regexp")); + string symbol_name_not_regex_str = sym_name_not_regex_prop + ? sym_name_not_regex_prop->get_value()->as_string() + : ""; + ini::simple_property_sptr sym_version_prop = is_simple_property(section.find_property("symbol_version")); string symbol_version = sym_version_prop @@ -3999,6 +4129,7 @@ read_variable_suppression(const ini::config::section& section) && soname_not_regex_str.empty() && symbol_name.empty() && symbol_name_regex_str.empty() + && symbol_name_not_regex_str.empty() && symbol_version.empty() && symbol_version_regex_str.empty() && type_name_str.empty() @@ -4015,12 +4146,16 @@ read_variable_suppression(const ini::config::section& section) || !name_regex_str.empty() || !name_not_regex_str.empty() || !symbol_name.empty() - || !symbol_name_regex_str.empty())) + || !symbol_name_regex_str.empty() + || !symbol_name_not_regex_str.empty())) result->set_drops_artifact_from_ir(true); if (!name_not_regex_str.empty()) result->set_name_not_regex_str(name_not_regex_str); + if (!symbol_name_not_regex_str.empty()) + result->set_symbol_name_not_regex_str(symbol_name_not_regex_str); + if (result && !change_kind_str.empty()) result->set_change_kind (variable_suppression::parse_change_kind(change_kind_str)); diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 54b3d6e3..657e4707 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -1224,6 +1224,15 @@ test-diff-suppr/test43-suppr-direct-fn-subtype-v0.o \ test-diff-suppr/test43-suppr-direct-fn-subtype-v1.cc \ test-diff-suppr/test43-suppr-direct-fn-subtype-v1.o \ test-diff-suppr/test43-suppr-direct-fn-subtype-report-1.txt \ +test-diff-suppr/test44-suppr-sym-name-not-regexp-report-1.txt \ +test-diff-suppr/test44-suppr-sym-name-not-regexp-report-2.txt \ +test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.c \ +test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.o \ +test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.o.abi \ +test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.c \ +test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.o \ +test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.o.abi \ +test-diff-suppr/test44-suppr-sym-name-not-regexp.suppr.txt \ \ test-diff-dwarf-abixml/test0-pr19026-libvtkIOSQL-6.1.so.1 \ test-diff-dwarf-abixml/test0-pr19026-libvtkIOSQL-6.1.so.1.abi \ diff --git a/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-1.txt b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-1.txt new file mode 100644 index 00000000..b1ba80e8 --- /dev/null +++ b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-1.txt @@ -0,0 +1,11 @@ +Functions changes summary: 1 Removed, 0 Changed, 0 Added function +Variables changes summary: 1 Removed, 0 Changed, 0 Added variable + +1 Removed function: + + 'function void test2()' {test2} + +1 Removed variable: + + 'char test2_variable' {test2_variable} + diff --git a/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-2.txt b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-2.txt new file mode 100644 index 00000000..73451c5a --- /dev/null +++ b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-2.txt @@ -0,0 +1,3 @@ +Functions changes summary: 0 Removed (1 filtered out), 0 Changed, 0 Added function +Variables changes summary: 0 Removed (1 filtered out), 0 Changed, 0 Added variable + diff --git a/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.c b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.c new file mode 100644 index 00000000..a2043f15 --- /dev/null +++ b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.c @@ -0,0 +1,4 @@ +int test1_variable = 0; +char test2_variable = 0; +void test1(){}; +void test2(){}; diff --git a/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.o b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.o new file mode 100644 index 00000000..e25819c3 Binary files /dev/null and b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.o differ diff --git a/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.o.abi b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.o.abi new file mode 100644 index 00000000..b54177ab --- /dev/null +++ b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.o.abi @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.c b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.c new file mode 100644 index 00000000..c85da958 --- /dev/null +++ b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.c @@ -0,0 +1,2 @@ +int test1_variable = 0; +void test1(){}; diff --git a/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.o b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.o new file mode 100644 index 00000000..b6c26761 Binary files /dev/null and b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.o differ diff --git a/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.o.abi b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.o.abi new file mode 100644 index 00000000..2d456da6 --- /dev/null +++ b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.o.abi @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp.suppr.txt b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp.suppr.txt new file mode 100644 index 00000000..343de25a --- /dev/null +++ b/tests/data/test-diff-suppr/test44-suppr-sym-name-not-regexp.suppr.txt @@ -0,0 +1,5 @@ +[suppress_function] + symbol_name_not_regexp = test1 + +[suppress_variable] + symbol_name_not_regexp = test1_variable diff --git a/tests/test-diff-suppr.cc b/tests/test-diff-suppr.cc index 55f8f850..9fe67db8 100644 --- a/tests/test-diff-suppr.cc +++ b/tests/test-diff-suppr.cc @@ -1778,6 +1778,46 @@ InOutSpec in_out_specs[] = "data/test-diff-suppr/test43-suppr-direct-fn-subtype-report-1.txt", "output/test-diff-suppr/test43-suppr-direct-fn-subtype-report-1.txt" }, + { + "data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.o", + "data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.o", + "", + "", + "", + "--no-default-suppression", + "data/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-1.txt", + "output/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-1.txt" + }, + { + "data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.o", + "data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.o", + "", + "", + "data/test-diff-suppr/test44-suppr-sym-name-not-regexp.suppr.txt", + "--no-default-suppression", + "data/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-2.txt", + "output/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-2.txt" + }, + { + "data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.o.abi", + "data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.o.abi", + "", + "", + "", + "--no-default-suppression", + "data/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-1.txt", + "output/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-1.txt" + }, + { + "data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v0.o.abi", + "data/test-diff-suppr/test44-suppr-sym-name-not-regexp-v1.o.abi", + "", + "", + "data/test-diff-suppr/test44-suppr-sym-name-not-regexp.suppr.txt", + "--no-default-suppression", + "data/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-2.txt", + "output/test-diff-suppr/test44-suppr-sym-name-not-regexp-report-2.txt" + }, // This should be the last entry {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} };