Support Linux Kernel ABI whitelist files

Enterprise Linux (at least) kernels come with ABI whitelist files that list the
names of the set of functions to be considered when looking at the ABI
exposed by the kernel to its modules.

This patch adds a new --linux-kernel-abi-whitelist option to abidiff
so that it drops changes that relate to functions that are *NOT*
defined in the whitelist.

The patch reads the whitelist file and generates one or several
instances of function_suppression that are applied when the two
binaries are loaded.

	* include/abg-suppression.h
	(function_suppression::function_suppression): Make the declaration
	of the default constructor public.
	* src/abg-suppression-priv.h (function_suppression::priv::priv):
	Declare a default constructor.
	* src/abg-suppression.cc
	(function_suppression::function_suppression): Define default
	constructor.
	* include/abg-tools-utils.h
	(gen_suppr_spec_from_kernel_abi_whitelist): Declare new function.
	* src/abg-tools-utils.cc
	(gen_suppr_spec_from_kernel_abi_whitelist): Define new function.
	* tools/abidiff.cc (options::kernel_abi_whitelist_paths):
	(display_usage): Display a help string for the new
	--linux-kernel-abi-whitelist option.
	(parse_command_line): Parse the --linux-kernel-abi-whitelist from
	the command line.
	(maybe_check_suppression_files): Check the presence of the kernel
	abi whitelist files.
	(set_suppressions): Generate suppression specifications from the
	whitelist files.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2016-11-10 13:49:08 +01:00
parent fadfa1a6f6
commit 08e760221b
6 changed files with 130 additions and 6 deletions

View File

@ -401,9 +401,6 @@ class function_suppression : public suppression_base
struct priv;
typedef shared_ptr<priv> 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,

View File

@ -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();

View File

@ -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,

View File

@ -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

View File

@ -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.

View File

@ -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<string> suppression_paths;
vector<string> kernel_abi_whitelist_paths;
vector<string> drop_fn_regex_patterns;
vector<string> drop_var_regex_patterns;
vector<string> 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<string>::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<string>::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