diff --git a/include/abg-suppression.h b/include/abg-suppression.h index 6c354799..57c681f6 100644 --- a/include/abg-suppression.h +++ b/include/abg-suppression.h @@ -401,9 +401,6 @@ class function_suppression : public suppression_base struct priv; typedef shared_ptr priv_sptr; - // Forbid this. - function_suppression(); - public: priv_sptr priv_; @@ -435,6 +432,8 @@ public: | DELETED_FUNCTION_CHANGE_KIND) }; + function_suppression(); + function_suppression(const string& label, const string& name, const string& name_regex, diff --git a/include/abg-tools-utils.h b/include/abg-tools-utils.h index 39caae6c..b649d7f1 100644 --- a/include/abg-tools-utils.h +++ b/include/abg-tools-utils.h @@ -60,6 +60,10 @@ bool string_is_ascii_identifier(const string&); suppr::type_suppression_sptr gen_suppr_spec_from_headers(const string& hdrs_root_dir); +bool +gen_suppr_spec_from_kernel_abi_whitelist(const string& abi_whitelist_path, + suppr::suppressions_type& s); + string get_default_system_suppression_file_path(); diff --git a/src/abg-suppression-priv.h b/src/abg-suppression-priv.h index 34379c1e..90702231 100644 --- a/src/abg-suppression-priv.h +++ b/src/abg-suppression-priv.h @@ -277,6 +277,11 @@ struct function_suppression::priv mutable sptr_utils::regex_t_sptr symbol_version_regex_; bool allow_other_aliases_; + priv(): + change_kind_(ALL_CHANGE_KIND), + allow_other_aliases_(true) + {} + priv(const string& name, const string& name_regex_str, const string& return_type_name, diff --git a/src/abg-suppression.cc b/src/abg-suppression.cc index 69304c9c..6e069183 100644 --- a/src/abg-suppression.cc +++ b/src/abg-suppression.cc @@ -1816,6 +1816,15 @@ function_suppression::parameter_spec::set_parameter_type_name_regex_str (const string& type_name_regex_str) {priv_->type_name_regex_str_ = type_name_regex_str;} +/// Default constructor for the @ref function_suppression type. +/// +/// It defines no suppression for now. Suppressions have to be +/// specified by using the various accessors of the @ref +/// function_suppression type. +function_suppression::function_suppression() + : suppression_base(/*label=*/""), priv_(new priv) +{} + /// Constructor for the @ref function_suppression type. /// /// @param label an informative text string that the evalution code diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc index d68fe06c..0b2457a6 100644 --- a/src/abg-tools-utils.cc +++ b/src/abg-tools-utils.cc @@ -50,6 +50,7 @@ namespace abigail { using namespace abigail::suppr; +using namespace abigail::ini; /// @brief Namespace for a set of utility function used by tools based /// on libabigail. @@ -888,6 +889,84 @@ gen_suppr_spec_from_headers(const string& headers_root_dir) return result; } +/// Generate a suppression specification from kernel abi whitelist +/// files. +/// +/// A kernel ABI whitelist file is an INI file that usually has only +/// one section. The name of the section is a string that ends up +/// with the sub-string "whitelist". For instance +/// RHEL7_x86_64_whitelist. +/// +/// Then the content of the section is a set of function names, one +/// name per line. Each function names is the name of a function +/// whose changes are to be keept. +/// +/// This function reads the white list and generate +/// function_suppression_sptr (or several, if there are more than one +/// section) that is added to a vector of suppressions. +/// +/// @param abi_whitelist_path the path to the Kernel ABI whitelist. +/// +/// @param supprs the resulting vector of suppressions to which the +/// new function suppressions resulting from reading the whitelist are +/// added. This vector is updated iff the function returns true. +/// +/// @return true iff the abi whitelist file was read and function +/// suppressions could be generated as a result. +bool +gen_suppr_spec_from_kernel_abi_whitelist(const string& abi_whitelist_path, + suppressions_type& supprs) +{ + config whitelist; + if (!read_config(abi_whitelist_path, whitelist)) + return false; + + bool created_a_suppr = false; + + const config::sections_type &whitelist_sections = whitelist.get_sections(); + for (config::sections_type::const_iterator s = + whitelist_sections.begin(); + s != whitelist_sections.end(); + ++s) + { + string section_name = (*s)->get_name(); + if (!string_ends_with(section_name, "whitelist")) + continue; + + function_suppression_sptr suppr; + string function_names_regexp; + for (config::properties_type::const_iterator p = + (*s)->get_properties().begin(); + p != (*s)->get_properties().end(); + ++p) + { + if (simple_property_sptr prop = is_simple_property(*p)) + if (prop->has_empty_value()) + { + const string &function_name = prop->get_name(); + if (!function_name.empty()) + { + if (!function_names_regexp.empty()) + function_names_regexp += "|"; + function_names_regexp += "^" + function_name + "$"; + } + } + } + + if (!function_names_regexp.empty()) + { + suppr.reset(new function_suppression); + suppr->set_label(section_name); + suppr->set_name_not_regex_str(function_names_regexp); + suppr->set_drops_artifact_from_ir(true); + supprs.push_back(suppr); + created_a_suppr = true; + } + } + + return created_a_suppr; +} + /// Get the path to the default system suppression file. /// /// @return a copy of the default system suppression file. diff --git a/tools/abidiff.cc b/tools/abidiff.cc index 28230acf..2ebe1130 100644 --- a/tools/abidiff.cc +++ b/tools/abidiff.cc @@ -56,6 +56,7 @@ using abigail::tools_utils::emit_prefix; using abigail::tools_utils::check_file; using abigail::tools_utils::guess_file_type; using abigail::tools_utils::gen_suppr_spec_from_headers; +using abigail::tools_utils::gen_suppr_spec_from_kernel_abi_whitelist; using abigail::tools_utils::load_default_system_suppressions; using abigail::tools_utils::load_default_user_suppressions; using abigail::tools_utils::abidiff_status; @@ -69,6 +70,7 @@ struct options string file1; string file2; vector suppression_paths; + vector kernel_abi_whitelist_paths; vector drop_fn_regex_patterns; vector drop_var_regex_patterns; vector keep_fn_regex_patterns; @@ -151,6 +153,8 @@ display_usage(const string& prog_name, ostream& out) "internal representation\n" << " --no-linux-kernel-mode don't consider the input binaries as " "linux kernel binaries\n" + << " --linux-kernel-abi-whitelist|--lkaw path to a " + "linux kernel abi whitelist\n" << " --stat only display the diff stats\n" << " --symtabs only display the symbol tables of the corpora\n" << " --no-default-suppression don't load any " @@ -280,8 +284,19 @@ parse_command_line(int argc, char* argv[], options& opts) opts.headers_dir2 = argv[j]; ++i; } - else if (!strcmp(argv[i], "--no-linux-kernel-mode")) - opts.linux_kernel_mode = false; + else if (!strcmp(argv[i], "--linux-kernel-abi-whitelist") + || !strcmp(argv[i], "--lkaw")) + { + int j = i + 1; + if (j >= argc) + { + opts.missing_operand = true; + opts.wrong_option = argv[i]; + return true; + } + opts.kernel_abi_whitelist_paths.push_back(argv[j]); + ++i; + } else if (!strcmp(argv[i], "--stat")) opts.show_stats_only = true; else if (!strcmp(argv[i], "--symtabs")) @@ -533,6 +548,13 @@ maybe_check_suppression_files(const options& opts) if (!check_file(*i, cerr, "abidiff")) return false; + for (vector::const_iterator i = + opts.kernel_abi_whitelist_paths.begin(); + i != opts.kernel_abi_whitelist_paths.end(); + ++i) + if (!check_file(*i, cerr, "abidiff")) + return false; + return true; } @@ -673,7 +695,13 @@ set_suppressions(ReadContextType& read_ctxt, const options& opts) } } - add_read_context_suppressions(read_ctxt, supprs); + for (vector::const_iterator i = + opts.kernel_abi_whitelist_paths.begin(); + i != opts.kernel_abi_whitelist_paths.end(); + ++i) + gen_suppr_spec_from_kernel_abi_whitelist(*i, supprs); + + add_read_context_suppressions(read_ctxt, supprs); } /// Set the regex patterns describing the functions to drop from the