abidw: Add --{follow,list}-dependencies & --add-binaries support

This implements the --follow-dependencies , --list-dependencies,
--add-binaries <foo,bar,...> and --added-binaries-dir options for the
abidw command, as documented in the
README-ABIDIFF-BINARIES-SET-SUPPORT.md file.

	* tools/abidw.cc (options::{added_bins_dirs, added_bins,
	follow_dependencies, list_dependencies}): Add new data members.
	(options::options): Initialize follow_dependencies and
	list_dependencies.
	(display_usage): Add usage strings for --add-binaries,
	--follow-dependencies, --list-dependencies, --added-binaries-dir.
	(parse_command_line): Parse options --add-binaries,
	--follow-dependencies, --list-dependencies, --added-binaries-dir.
	(load_corpus_and_write_abixml): Implement the --list-dependencies,
	--follow-dependencies and --add-binaries sub-commands.
	* doc/manuals/abidw.rst: Document the --add-binaries,
	--follow-dependencies, --list-dependencies, --added-binaries-dir
	options.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2023-06-24 16:10:40 +02:00
parent a30a3146b5
commit 3e568fef6b
2 changed files with 190 additions and 7 deletions

View File

@ -44,14 +44,49 @@ Options
Display a short help about the command and exit.
* `--version | -v`
* ``--version | -v``
Display the version of the program and exit.
* `--abixml-version`
* ``--abixml-version``
Display the version of the ABIXML format emitted by this program and exit.
* ``--add-binaries`` <*bin1,bin2,...*>
For each of the comma-separated binaries given in argument to this
option, if the binary is found in the directory specified by the
`--added-binaries-dir` option, then load the ABI corpus of the
binary and add it to a set of ABI corpora (called a ABI Corpus
Group) made of the binary denoted by the Argument of
``abidw``. That corpus group is then serialized out.
* ``--follow-dependencies``
For each dependency of the input binary of ``abidw``, if it is
found in the directory specified by the ``--added-binaries-dir``
option, then construct an ABI corpus out of the dependency and add
it to a set of ABI corpora (called an ABI Corpus Group) along with
the ABI corpus of the input binary of the program. The ABI Corpus
Group is then serialized out.
* ``--list-dependencies``
For each dependency of the input binary of``abidw``, if it's found
in the directory specified by the ``--added-binaries-dir`` option,
then the name of the dependency is printed out.
* ``--added-binaries-dir | --abd`` <*dir-path*>
This option is to be used in conjunction with the
``--add-binaries``, the ``--follow-dependencies`` or the
``--list-dependencies`` option. Binaries listed as arguments of
the ``--add-binaries`` option or being dependencies of the input
binary in the case of the ``--follow-dependencies`` option and
found in the directory <*dir-path*> are going to be loaded as ABI
corpus and added to the set of ABI corpora (called an ABI corpus
group) built and serialized.
* ``--debug-info-dir | -d`` <*dir-path*>
In cases where the debug info for *path-to-elf-file* is in a
@ -368,6 +403,39 @@ Options
Emit verbose logs about the progress of miscellaneous internal
things.
Usage examples
==============
1. Emitting an ``ABIXML`` representation of a binary: ::
$ abidw binary > binary.abi
2. Emitting an ``ABIXML`` representation of a set of binaries
specified on the command line: ::
$ abidw --added-binaries=bin1,bin2,bin3 \
--added-binaries-dir /some/where \
binary > binaries.abi
Note that the binaries bin1, bin2 and bin3 are to be found in the
directory ``/some/where``. A representation of the ABI of the
set of binaries ``binary, bin1, bin2`` and ``bin3`` called an
``ABI corpus group`` is serialized in the file binaries.abi.
3. Emitting an ``ABIXML`` representation of a binary and its
dependencies: ::
$ abidw --follow-dependencies \
--added-binaries-dir /some/where \
binary > binary.abi
Note that only the dependencies that are found in the directory
``/some/where`` are analysed. Their ABIs, along with the ABI the
binary named ``binary`` are represented as an ABI corpus group
and serialized in the file ``binary.abi``, in the ABIXML format.
Notes
=====

View File

@ -22,6 +22,7 @@
#include <memory>
#include <string>
#include <vector>
#include <set>
#include "abg-config.h"
#include "abg-tools-utils.h"
#include "abg-corpus.h"
@ -43,7 +44,9 @@ using std::cout;
using std::ostream;
using std::ofstream;
using std::vector;
using std::set;
using std::shared_ptr;
using std::static_pointer_cast;
using abg_compat::optional;
using abigail::tools_utils::emit_prefix;
using abigail::tools_utils::temp_file;
@ -52,6 +55,9 @@ using abigail::tools_utils::check_file;
using abigail::tools_utils::build_corpus_group_from_kernel_dist_under;
using abigail::tools_utils::timer;
using abigail::tools_utils::create_best_elf_based_reader;
using abigail::tools_utils::stick_corpus_and_dependencies_into_corpus_group;
using abigail::tools_utils::stick_corpus_and_binaries_into_corpus_group;
using abigail::tools_utils::add_dependencies_into_corpus_group;
using abigail::ir::environment_sptr;
using abigail::ir::environment;
using abigail::corpus;
@ -71,6 +77,7 @@ using abigail::xml_writer::create_write_context;
using abigail::xml_writer::type_id_style_kind;
using abigail::xml_writer::write_context_sptr;
using abigail::xml_writer::write_corpus;
using abigail::xml_writer::write_corpus_group;
using abigail::abixml::read_corpus_from_abixml_file;
using namespace abigail;
@ -84,6 +91,8 @@ struct options
vector<char**> prepared_di_root_paths;
vector<string> headers_dirs;
vector<string> header_files;
vector<string> added_bins_dirs;
vector<string> added_bins;
string vmlinux;
vector<string> suppression_paths;
vector<string> kabi_whitelist_paths;
@ -104,6 +113,8 @@ struct options
bool corpus_group_for_linux;
bool show_stats;
bool noout;
bool follow_dependencies;
bool list_dependencies;
#ifdef WITH_CTF
bool use_ctf;
#endif
@ -148,6 +159,8 @@ struct options
corpus_group_for_linux(false),
show_stats(),
noout(),
follow_dependencies(),
list_dependencies(),
#ifdef WITH_CTF
use_ctf(false),
#endif
@ -229,6 +242,12 @@ display_usage(const string& prog_name, ostream& out)
<< " --vmlinux <path> the path to the vmlinux binary to consider to emit "
"the ABI of the union of vmlinux and its modules\n"
<< " --abidiff compare the loaded ABI against itself\n"
<< " --add-binaries <bin1,bin2,...> build a corpus group with "
"the added inaries\n"
<< " --follow-dependencies build a corpus group with the dependencies\n"
<< " --list-dependencies list the dependencies of a given binary\n"
<< " --added-binaries-dir|--abd <dir-of-deps> where to look for dependencies "
"or added binaries\n"
#ifdef WITH_DEBUG_SELF_COMPARISON
<< " --debug-abidiff debug the process of comparing the loaded ABI against itself\n"
#endif
@ -294,6 +313,15 @@ parse_command_line(int argc, char* argv[], options& opts)
opts.headers_dirs.push_back(argv[j]);
++i;
}
else if (!strcmp(argv[i], "--added-binaries-dir")
|| !strcmp(argv[i], "--abd"))
{
int j = i + 1;
if (j >= argc)
return false;
opts.added_bins_dirs.push_back(argv[j]);
++i;
}
else if (!strcmp(argv[i], "--header-file")
|| !strcmp(argv[i], "--hf"))
{
@ -344,6 +372,28 @@ parse_command_line(int argc, char* argv[], options& opts)
}
else if (!strcmp(argv[i], "--noout"))
opts.noout = true;
else if (!strcmp(argv[i], "--follow-dependencies"))
opts.follow_dependencies = true;
else if (!strcmp(argv[i], "--list-dependencies"))
opts.list_dependencies = true;
else if (!strncmp(argv[i], "--add-binaries=",
strlen("--add-binaries=")))
tools_utils::get_comma_separated_args_of_option(argv[i],
"--add-binaries=",
opts.added_bins);
else if (!strcmp(argv[i], "--add-binaries"))
{
int j = i + 1;
if (j >= argc)
return false;
string s = argv[j];
if (s.find(','))
tools_utils::split_string(s, ",", opts.added_bins);
else
opts.added_bins.push_back(s);
++i;
}
#ifdef WITH_CTF
else if (!strcmp(argv[i], "--ctf"))
opts.use_ctf = true;
@ -598,6 +648,7 @@ load_corpus_and_write_abixml(char* argv[],
#endif
corpus_sptr corp;
corpus_group_sptr corp_group;
fe_iface::status s = fe_iface::STATUS_UNKNOWN;
corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
#ifdef WITH_CTF
@ -720,6 +771,50 @@ load_corpus_and_write_abixml(char* argv[],
return 1;
}
if (opts.list_dependencies)
{
// Show the dependencies of the corpus and display them.
set<string> dependencies;
if (tools_utils::get_dependencies(*corp, opts.added_bins_dirs,
dependencies))
{
cout << "Dependencies of '" << corp->get_path()
<< "':\n\t";
int n = 0;
for (const auto& dep : dependencies)
{
if (n)
cout << ", ";
cout << dep;
++n;
}
cout << "\n";
}
}
if (!opts.added_bins.empty())
corp_group =
stick_corpus_and_binaries_into_corpus_group(reader, corp,
opts.added_bins,
opts.added_bins_dirs);
if (opts.follow_dependencies)
{
// load the dependencies of the corpus and put them all into a
// corpus group.
// If a corpus_group already exists, use that one ...
if (!corp_group->is_empty())
add_dependencies_into_corpus_group(reader, *corp,
opts.added_bins_dirs,
*corp_group);
else
// .. otherwise, create a new corpus group.
corp_group =
stick_corpus_and_dependencies_into_corpus_group(reader, corp,
opts.added_bins_dirs);
}
// Clear some resources to gain back some space.
t.start();
reader.reset();
@ -744,6 +839,9 @@ load_corpus_and_write_abixml(char* argv[],
// against the ABI of the input ELF file.
temp_file_sptr tmp_file = temp_file::create();
set_ostream(*write_ctxt, tmp_file->get_stream());
if (corp_group)
write_corpus_group(*write_ctxt, corp_group, 0);
else
write_corpus(*write_ctxt, corp, 0);
tmp_file->get_stream().flush();
@ -763,7 +861,14 @@ load_corpus_and_write_abixml(char* argv[],
#endif
t.start();
fe_iface::status sts;
corpus_sptr corp2 = rdr->read_corpus(sts);
corpus_sptr corp2;
corpus_group_sptr corp_group2;
if (corp_group)
corp_group2 = abixml::read_corpus_group_from_input(*rdr);
else
corp2 = rdr->read_corpus(sts);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
@ -781,7 +886,11 @@ load_corpus_and_write_abixml(char* argv[],
set_diff_context(ctxt);
ctxt->show_locs(opts.show_locs);
t.start();
corpus_diff_sptr diff = compute_diff(corp, corp2, ctxt);
corpus_diff_sptr diff =
corp_group2
? compute_diff(corp_group, corp_group2, ctxt)
: compute_diff(corp, corp2, ctxt);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
@ -822,6 +931,9 @@ load_corpus_and_write_abixml(char* argv[],
}
set_ostream(*write_ctxt, of);
t.start();
if (corp_group)
write_corpus_group(*write_ctxt, corp_group, 0);
else
write_corpus(*write_ctxt, corp, 0);
t.stop();
if (opts.do_log)
@ -833,7 +945,10 @@ load_corpus_and_write_abixml(char* argv[],
else
{
t.start();
exit_code = !write_corpus(*write_ctxt, corp, 0);
exit_code =
corp_group
? !write_corpus_group(*write_ctxt, corp_group, 0)
: !write_corpus(*write_ctxt, corp, 0);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)