Hello,
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>
Applied to master.
---
doc/manuals/abidw.rst | 72 +++++++++++++++++++++++-
tools/abidw.cc | 125 ++++++++++++++++++++++++++++++++++++++++--
2 files changed, 190 insertions(+), 7 deletions(-)
@@ -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
=====
@@ -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,7 +839,10 @@ 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());
- write_corpus(*write_ctxt, corp, 0);
+ if (corp_group)
+ write_corpus_group(*write_ctxt, corp_group, 0);
+ else
+ write_corpus(*write_ctxt, corp, 0);
tmp_file->get_stream().flush();
#ifdef WITH_DEBUG_SELF_COMPARISON
@@ -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,7 +931,10 @@ load_corpus_and_write_abixml(char* argv[],
}
set_ostream(*write_ctxt, of);
t.start();
- write_corpus(*write_ctxt, corp, 0);
+ if (corp_group)
+ write_corpus_group(*write_ctxt, corp_group, 0);
+ else
+ write_corpus(*write_ctxt, corp, 0);
t.stop();
if (opts.do_log)
emit_prefix(argv[0], cerr)
@@ -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)