1e01aa904Sopenharmony_ci// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2e01aa904Sopenharmony_ci// -*- Mode: C++ -*-
3e01aa904Sopenharmony_ci//
4e01aa904Sopenharmony_ci// Copyright (C) 2015-2022 Red Hat, Inc.
5e01aa904Sopenharmony_ci//
6e01aa904Sopenharmony_ci// Author: Sinny Kumari
7e01aa904Sopenharmony_ci
8e01aa904Sopenharmony_ci/// @file
9e01aa904Sopenharmony_ci
10e01aa904Sopenharmony_ci/// This program compares the ABIs of binaries inside two packages.
11e01aa904Sopenharmony_ci///
12e01aa904Sopenharmony_ci/// For now, the supported package formats are Deb and RPM, but
13e01aa904Sopenharmony_ci/// support for other formats would be greatly appreciated.
14e01aa904Sopenharmony_ci///
15e01aa904Sopenharmony_ci/// The program takes the two packages to compare as well as their
16e01aa904Sopenharmony_ci/// associated debug info packages.
17e01aa904Sopenharmony_ci///
18e01aa904Sopenharmony_ci/// The program extracts the content of the two packages into a
19e01aa904Sopenharmony_ci/// temporary directory , looks for the ELF binaries in there,
20e01aa904Sopenharmony_ci/// compares their ABIs and emit a report about the changes.
21e01aa904Sopenharmony_ci/// As this program uses libpthread to perform several tasks
22e01aa904Sopenharmony_ci/// concurrently, here is a coarse grain description of the sequence
23e01aa904Sopenharmony_ci/// of actions performed, including where things are done
24e01aa904Sopenharmony_ci/// concurrently.
25e01aa904Sopenharmony_ci///
26e01aa904Sopenharmony_ci/// (steps 1/ and 2/ are performed concurrently.  Then steps 3/ and 4/
27e01aa904Sopenharmony_ci/// are performed in sequence)
28e01aa904Sopenharmony_ci///
29e01aa904Sopenharmony_ci/// 1/ the first package and its ancillary packages (debug info and
30e01aa904Sopenharmony_ci/// devel packages) are extracted concurrently.
31e01aa904Sopenharmony_ci/// There is one thread per package being extracted.  So if there are
32e01aa904Sopenharmony_ci/// 3 thread packages (one package, one debug info package and one
33e01aa904Sopenharmony_ci/// devel package), then there are 3 threads to extracts them.  Then
34e01aa904Sopenharmony_ci/// when the extracting is done, another thread performs the analysis
35e01aa904Sopenharmony_ci/// of th1 extracted content.
36e01aa904Sopenharmony_ci///
37e01aa904Sopenharmony_ci/// 2/ A similar thing is done for the second package.
38e01aa904Sopenharmony_ci///
39e01aa904Sopenharmony_ci/// 3/ comparisons are performed concurrently.
40e01aa904Sopenharmony_ci///
41e01aa904Sopenharmony_ci/// 4/ the reports are then emitted to standard output, always in the same
42e01aa904Sopenharmony_ci/// order.
43e01aa904Sopenharmony_ci
44e01aa904Sopenharmony_ci
45e01aa904Sopenharmony_ci// In case we have a bad fts we include this before config.h because
46e01aa904Sopenharmony_ci// it can't handle _FILE_OFFSET_BITS.  Everything we need here is fine
47e01aa904Sopenharmony_ci// if its declarations just come first.  Also, include sys/types.h
48e01aa904Sopenharmony_ci// before fts. On some systems fts.h is not self contained.
49e01aa904Sopenharmony_ci#ifdef BAD_FTS
50e01aa904Sopenharmony_ci  #include <sys/types.h>
51e01aa904Sopenharmony_ci  #include <fts.h>
52e01aa904Sopenharmony_ci#endif
53e01aa904Sopenharmony_ci
54e01aa904Sopenharmony_ci// For package configuration macros.
55e01aa904Sopenharmony_ci#include "config.h"
56e01aa904Sopenharmony_ci
57e01aa904Sopenharmony_ci#include <assert.h>
58e01aa904Sopenharmony_ci#include <fcntl.h>
59e01aa904Sopenharmony_ci#include <sys/stat.h>
60e01aa904Sopenharmony_ci
61e01aa904Sopenharmony_ci// If fts.h is included before config.h, its indirect inclusions may
62e01aa904Sopenharmony_ci// not give us the right LFS aliases of these functions, so map them
63e01aa904Sopenharmony_ci// manually.
64e01aa904Sopenharmony_ci#ifdef BAD_FTS
65e01aa904Sopenharmony_ci  #ifdef _FILE_OFFSET_BITS
66e01aa904Sopenharmony_ci    #define open open64
67e01aa904Sopenharmony_ci    #define fopen fopen64
68e01aa904Sopenharmony_ci  #endif
69e01aa904Sopenharmony_ci#else
70e01aa904Sopenharmony_ci  #include <sys/types.h>
71e01aa904Sopenharmony_ci  #include <fts.h>
72e01aa904Sopenharmony_ci#endif
73e01aa904Sopenharmony_ci
74e01aa904Sopenharmony_ci#include <algorithm>
75e01aa904Sopenharmony_ci#include <cstdlib>
76e01aa904Sopenharmony_ci#include <cstring>
77e01aa904Sopenharmony_ci#include <fstream>
78e01aa904Sopenharmony_ci#include <iostream>
79e01aa904Sopenharmony_ci#include <map>
80e01aa904Sopenharmony_ci#include <memory>
81e01aa904Sopenharmony_ci#include <string>
82e01aa904Sopenharmony_ci#include <unordered_set>
83e01aa904Sopenharmony_ci#include <vector>
84e01aa904Sopenharmony_ci
85e01aa904Sopenharmony_ci#include "abg-workers.h"
86e01aa904Sopenharmony_ci#include "abg-config.h"
87e01aa904Sopenharmony_ci#include "abg-tools-utils.h"
88e01aa904Sopenharmony_ci#include "abg-comparison.h"
89e01aa904Sopenharmony_ci#include "abg-suppression.h"
90e01aa904Sopenharmony_ci#include "abg-dwarf-reader.h"
91e01aa904Sopenharmony_ci#include "abg-reader.h"
92e01aa904Sopenharmony_ci#include "abg-writer.h"
93e01aa904Sopenharmony_ci#ifdef WITH_CTF
94e01aa904Sopenharmony_ci#include "abg-ctf-reader.h"
95e01aa904Sopenharmony_ci#endif
96e01aa904Sopenharmony_ci
97e01aa904Sopenharmony_ciusing std::cout;
98e01aa904Sopenharmony_ciusing std::cerr;
99e01aa904Sopenharmony_ciusing std::string;
100e01aa904Sopenharmony_ciusing std::ostream;
101e01aa904Sopenharmony_ciusing std::ofstream;
102e01aa904Sopenharmony_ciusing std::vector;
103e01aa904Sopenharmony_ciusing std::map;
104e01aa904Sopenharmony_ciusing std::unordered_set;
105e01aa904Sopenharmony_ciusing std::set;
106e01aa904Sopenharmony_ciusing std::ostringstream;
107e01aa904Sopenharmony_ciusing std::shared_ptr;
108e01aa904Sopenharmony_ciusing std::dynamic_pointer_cast;
109e01aa904Sopenharmony_ciusing abg_compat::optional;
110e01aa904Sopenharmony_ciusing abigail::workers::task;
111e01aa904Sopenharmony_ciusing abigail::workers::task_sptr;
112e01aa904Sopenharmony_ciusing abigail::workers::queue;
113e01aa904Sopenharmony_ciusing abigail::tools_utils::maybe_get_symlink_target_file_path;
114e01aa904Sopenharmony_ciusing abigail::tools_utils::file_exists;
115e01aa904Sopenharmony_ciusing abigail::tools_utils::is_dir;
116e01aa904Sopenharmony_ciusing abigail::tools_utils::emit_prefix;
117e01aa904Sopenharmony_ciusing abigail::tools_utils::check_file;
118e01aa904Sopenharmony_ciusing abigail::tools_utils::ensure_dir_path_created;
119e01aa904Sopenharmony_ciusing abigail::tools_utils::guess_file_type;
120e01aa904Sopenharmony_ciusing abigail::tools_utils::string_ends_with;
121e01aa904Sopenharmony_ciusing abigail::tools_utils::dir_name;
122e01aa904Sopenharmony_ciusing abigail::tools_utils::real_path;
123e01aa904Sopenharmony_ciusing abigail::tools_utils::string_suffix;
124e01aa904Sopenharmony_ciusing abigail::tools_utils::sorted_strings_common_prefix;
125e01aa904Sopenharmony_ciusing abigail::tools_utils::file_type;
126e01aa904Sopenharmony_ciusing abigail::tools_utils::make_path_absolute;
127e01aa904Sopenharmony_ciusing abigail::tools_utils::base_name;
128e01aa904Sopenharmony_ciusing abigail::tools_utils::get_rpm_arch;
129e01aa904Sopenharmony_ciusing abigail::tools_utils::file_is_kernel_package;
130e01aa904Sopenharmony_ciusing abigail::tools_utils::gen_suppr_spec_from_headers;
131e01aa904Sopenharmony_ciusing abigail::tools_utils::get_default_system_suppression_file_path;
132e01aa904Sopenharmony_ciusing abigail::tools_utils::get_default_user_suppression_file_path;
133e01aa904Sopenharmony_ciusing abigail::tools_utils::get_vmlinux_path_from_kernel_dist;
134e01aa904Sopenharmony_ciusing abigail::tools_utils::get_dsos_provided_by_rpm;
135e01aa904Sopenharmony_ciusing abigail::tools_utils::build_corpus_group_from_kernel_dist_under;
136e01aa904Sopenharmony_ciusing abigail::tools_utils::load_default_system_suppressions;
137e01aa904Sopenharmony_ciusing abigail::tools_utils::load_default_user_suppressions;
138e01aa904Sopenharmony_ciusing abigail::tools_utils::abidiff_status;
139e01aa904Sopenharmony_ciusing abigail::tools_utils::create_best_elf_based_reader;
140e01aa904Sopenharmony_ciusing abigail::ir::corpus_sptr;
141e01aa904Sopenharmony_ciusing abigail::ir::corpus_group_sptr;
142e01aa904Sopenharmony_ciusing abigail::comparison::diff_context;
143e01aa904Sopenharmony_ciusing abigail::comparison::diff_context_sptr;
144e01aa904Sopenharmony_ciusing abigail::comparison::compute_diff;
145e01aa904Sopenharmony_ciusing abigail::comparison::corpus_diff_sptr;
146e01aa904Sopenharmony_ciusing abigail::comparison::get_default_harmless_categories_bitmap;
147e01aa904Sopenharmony_ciusing abigail::comparison::get_default_harmful_categories_bitmap;
148e01aa904Sopenharmony_ciusing abigail::suppr::suppression_sptr;
149e01aa904Sopenharmony_ciusing abigail::suppr::suppressions_type;
150e01aa904Sopenharmony_ciusing abigail::suppr::read_suppressions;
151e01aa904Sopenharmony_ciusing abigail::elf::get_soname_of_elf_file;
152e01aa904Sopenharmony_ciusing abigail::elf::get_type_of_elf_file;
153e01aa904Sopenharmony_ciusing abigail::xml_writer::create_write_context;
154e01aa904Sopenharmony_ciusing abigail::xml_writer::write_context_sptr;
155e01aa904Sopenharmony_ciusing abigail::xml_writer::write_corpus;
156e01aa904Sopenharmony_ci
157e01aa904Sopenharmony_ciusing namespace abigail;
158e01aa904Sopenharmony_ci
159e01aa904Sopenharmony_ciclass package;
160e01aa904Sopenharmony_ci
161e01aa904Sopenharmony_ci/// Convenience typedef for a shared pointer to a @ref package.
162e01aa904Sopenharmony_citypedef shared_ptr<package> package_sptr;
163e01aa904Sopenharmony_ci
164e01aa904Sopenharmony_ci/// The options passed to the current program.
165e01aa904Sopenharmony_ciclass options
166e01aa904Sopenharmony_ci{
167e01aa904Sopenharmony_ci  options();
168e01aa904Sopenharmony_ci
169e01aa904Sopenharmony_cipublic:
170e01aa904Sopenharmony_ci  string	wrong_option;
171e01aa904Sopenharmony_ci  string	wrong_arg;
172e01aa904Sopenharmony_ci  string	prog_name;
173e01aa904Sopenharmony_ci  bool		display_usage;
174e01aa904Sopenharmony_ci  bool		display_version;
175e01aa904Sopenharmony_ci  bool		missing_operand;
176e01aa904Sopenharmony_ci  bool		nonexistent_file;
177e01aa904Sopenharmony_ci  bool		abignore;
178e01aa904Sopenharmony_ci  bool		parallel;
179e01aa904Sopenharmony_ci  string	package1;
180e01aa904Sopenharmony_ci  string	package2;
181e01aa904Sopenharmony_ci  vector<string> debug_packages1;
182e01aa904Sopenharmony_ci  vector<string> debug_packages2;
183e01aa904Sopenharmony_ci  string	devel_package1;
184e01aa904Sopenharmony_ci  string	devel_package2;
185e01aa904Sopenharmony_ci  size_t	num_workers;
186e01aa904Sopenharmony_ci  bool		verbose;
187e01aa904Sopenharmony_ci  bool		drop_private_types;
188e01aa904Sopenharmony_ci  bool		show_relative_offset_changes;
189e01aa904Sopenharmony_ci  bool		no_default_suppression;
190e01aa904Sopenharmony_ci  bool		keep_tmp_files;
191e01aa904Sopenharmony_ci  bool		compare_dso_only;
192e01aa904Sopenharmony_ci  bool		compare_private_dsos;
193e01aa904Sopenharmony_ci  bool		leaf_changes_only;
194e01aa904Sopenharmony_ci  bool		show_all_types;
195e01aa904Sopenharmony_ci  bool		show_hexadecimal_values;
196e01aa904Sopenharmony_ci  bool		show_offsets_sizes_in_bits;
197e01aa904Sopenharmony_ci  bool		show_impacted_interfaces;
198e01aa904Sopenharmony_ci  bool		show_full_impact_report;
199e01aa904Sopenharmony_ci  bool		show_linkage_names;
200e01aa904Sopenharmony_ci  bool		show_redundant_changes;
201e01aa904Sopenharmony_ci  bool		show_harmless_changes;
202e01aa904Sopenharmony_ci  bool		show_locs;
203e01aa904Sopenharmony_ci  bool		show_added_syms;
204e01aa904Sopenharmony_ci  bool		show_symbols_not_referenced_by_debug_info;
205e01aa904Sopenharmony_ci  bool		show_added_binaries;
206e01aa904Sopenharmony_ci  bool		fail_if_no_debug_info;
207e01aa904Sopenharmony_ci  bool		show_identical_binaries;
208e01aa904Sopenharmony_ci  bool		leverage_dwarf_factorization;
209e01aa904Sopenharmony_ci  bool		assume_odr_for_cplusplus;
210e01aa904Sopenharmony_ci  bool		self_check;
211e01aa904Sopenharmony_ci  optional<bool> exported_interfaces_only;
212e01aa904Sopenharmony_ci#ifdef WITH_CTF
213e01aa904Sopenharmony_ci  bool		use_ctf;
214e01aa904Sopenharmony_ci#endif
215e01aa904Sopenharmony_ci
216e01aa904Sopenharmony_ci  vector<string> kabi_whitelist_packages;
217e01aa904Sopenharmony_ci  vector<string> suppression_paths;
218e01aa904Sopenharmony_ci  vector<string> kabi_whitelist_paths;
219e01aa904Sopenharmony_ci  suppressions_type kabi_suppressions;
220e01aa904Sopenharmony_ci  package_sptr  pkg1;
221e01aa904Sopenharmony_ci  package_sptr  pkg2;
222e01aa904Sopenharmony_ci
223e01aa904Sopenharmony_ci  options(const string& program_name)
224e01aa904Sopenharmony_ci    : prog_name(program_name),
225e01aa904Sopenharmony_ci      display_usage(),
226e01aa904Sopenharmony_ci      display_version(),
227e01aa904Sopenharmony_ci      missing_operand(),
228e01aa904Sopenharmony_ci      nonexistent_file(),
229e01aa904Sopenharmony_ci      abignore(true),
230e01aa904Sopenharmony_ci      parallel(true),
231e01aa904Sopenharmony_ci      verbose(),
232e01aa904Sopenharmony_ci      drop_private_types(),
233e01aa904Sopenharmony_ci      show_relative_offset_changes(true),
234e01aa904Sopenharmony_ci      no_default_suppression(),
235e01aa904Sopenharmony_ci      keep_tmp_files(),
236e01aa904Sopenharmony_ci      compare_dso_only(),
237e01aa904Sopenharmony_ci      compare_private_dsos(),
238e01aa904Sopenharmony_ci      leaf_changes_only(),
239e01aa904Sopenharmony_ci      show_all_types(),
240e01aa904Sopenharmony_ci      show_hexadecimal_values(),
241e01aa904Sopenharmony_ci      show_offsets_sizes_in_bits(true),
242e01aa904Sopenharmony_ci      show_impacted_interfaces(),
243e01aa904Sopenharmony_ci      show_full_impact_report(),
244e01aa904Sopenharmony_ci      show_linkage_names(true),
245e01aa904Sopenharmony_ci      show_redundant_changes(),
246e01aa904Sopenharmony_ci      show_harmless_changes(),
247e01aa904Sopenharmony_ci      show_locs(true),
248e01aa904Sopenharmony_ci      show_added_syms(true),
249e01aa904Sopenharmony_ci      show_symbols_not_referenced_by_debug_info(true),
250e01aa904Sopenharmony_ci      show_added_binaries(true),
251e01aa904Sopenharmony_ci      fail_if_no_debug_info(),
252e01aa904Sopenharmony_ci      show_identical_binaries(),
253e01aa904Sopenharmony_ci      leverage_dwarf_factorization(true),
254e01aa904Sopenharmony_ci      assume_odr_for_cplusplus(true),
255e01aa904Sopenharmony_ci      self_check()
256e01aa904Sopenharmony_ci#ifdef WITH_CTF
257e01aa904Sopenharmony_ci      ,
258e01aa904Sopenharmony_ci      use_ctf()
259e01aa904Sopenharmony_ci#endif
260e01aa904Sopenharmony_ci  {
261e01aa904Sopenharmony_ci    // set num_workers to the default number of threads of the
262e01aa904Sopenharmony_ci    // underlying maching.  This is the default value for the number
263e01aa904Sopenharmony_ci    // of workers to use in workers queues throughout the code.
264e01aa904Sopenharmony_ci    num_workers = abigail::workers::get_number_of_threads();
265e01aa904Sopenharmony_ci  }
266e01aa904Sopenharmony_ci};
267e01aa904Sopenharmony_ci
268e01aa904Sopenharmony_cistatic bool
269e01aa904Sopenharmony_ciget_interesting_files_under_dir(const string	dir,
270e01aa904Sopenharmony_ci				const string&	file_name_to_look_for,
271e01aa904Sopenharmony_ci				options&	opts,
272e01aa904Sopenharmony_ci				vector<string>& interesting_files);
273e01aa904Sopenharmony_ci
274e01aa904Sopenharmony_ci/// Abstract ELF files from the packages which ABIs ought to be
275e01aa904Sopenharmony_ci/// compared
276e01aa904Sopenharmony_ciclass elf_file
277e01aa904Sopenharmony_ci{
278e01aa904Sopenharmony_ciprivate:
279e01aa904Sopenharmony_ci  elf_file();
280e01aa904Sopenharmony_ci
281e01aa904Sopenharmony_cipublic:
282e01aa904Sopenharmony_ci  string				path;
283e01aa904Sopenharmony_ci  string				name;
284e01aa904Sopenharmony_ci  string				soname;
285e01aa904Sopenharmony_ci  off_t				size;
286e01aa904Sopenharmony_ci  abigail::elf::elf_type	type;
287e01aa904Sopenharmony_ci
288e01aa904Sopenharmony_ci  /// The path to the elf file.
289e01aa904Sopenharmony_ci  ///
290e01aa904Sopenharmony_ci  /// @param path the path to the elf file.
291e01aa904Sopenharmony_ci  elf_file(const string& path)
292e01aa904Sopenharmony_ci    : path(path)
293e01aa904Sopenharmony_ci   {
294e01aa904Sopenharmony_ci     abigail::tools_utils::base_name(path, name);
295e01aa904Sopenharmony_ci     get_soname_of_elf_file(path, soname);
296e01aa904Sopenharmony_ci     get_type_of_elf_file(path, type);
297e01aa904Sopenharmony_ci     struct stat estat;
298e01aa904Sopenharmony_ci     stat(path.c_str(), &estat);
299e01aa904Sopenharmony_ci     size = estat.st_size;
300e01aa904Sopenharmony_ci  }
301e01aa904Sopenharmony_ci};
302e01aa904Sopenharmony_ci
303e01aa904Sopenharmony_ci/// A convenience typedef for a shared pointer to elf_file.
304e01aa904Sopenharmony_citypedef shared_ptr<elf_file> elf_file_sptr;
305e01aa904Sopenharmony_ci
306e01aa904Sopenharmony_ci/// Abstract the result of comparing two packages.
307e01aa904Sopenharmony_ci///
308e01aa904Sopenharmony_ci/// This contains the the paths of the set of added binaries, removed
309e01aa904Sopenharmony_ci/// binaries, and binaries whic ABI changed.
310e01aa904Sopenharmony_cistruct abi_diff
311e01aa904Sopenharmony_ci{
312e01aa904Sopenharmony_ci  vector<elf_file_sptr> added_binaries;
313e01aa904Sopenharmony_ci  vector<elf_file_sptr> removed_binaries;
314e01aa904Sopenharmony_ci  vector<string> changed_binaries;
315e01aa904Sopenharmony_ci
316e01aa904Sopenharmony_ci  /// Test if the current diff carries changes.
317e01aa904Sopenharmony_ci  ///
318e01aa904Sopenharmony_ci  /// @return true iff the current diff carries changes.
319e01aa904Sopenharmony_ci  bool
320e01aa904Sopenharmony_ci  has_changes()
321e01aa904Sopenharmony_ci  {
322e01aa904Sopenharmony_ci    return (!added_binaries.empty()
323e01aa904Sopenharmony_ci	    || !removed_binaries.empty()
324e01aa904Sopenharmony_ci	    ||!changed_binaries.empty());
325e01aa904Sopenharmony_ci  }
326e01aa904Sopenharmony_ci};
327e01aa904Sopenharmony_ci
328e01aa904Sopenharmony_ci/// Abstracts a package.
329e01aa904Sopenharmony_ciclass package
330e01aa904Sopenharmony_ci{
331e01aa904Sopenharmony_cipublic:
332e01aa904Sopenharmony_ci
333e01aa904Sopenharmony_ci  /// The kind of package we are looking at.
334e01aa904Sopenharmony_ci  enum kind
335e01aa904Sopenharmony_ci  {
336e01aa904Sopenharmony_ci    /// Main package. Contains binaries to ABI-compare.
337e01aa904Sopenharmony_ci    KIND_MAIN = 0,
338e01aa904Sopenharmony_ci    /// Devel package.  Contains public headers files in which public
339e01aa904Sopenharmony_ci    /// types are defined.
340e01aa904Sopenharmony_ci    KIND_DEVEL,
341e01aa904Sopenharmony_ci    /// Debug info package.  Contains the debug info for the binaries
342e01aa904Sopenharmony_ci    /// int he main packge.
343e01aa904Sopenharmony_ci    KIND_DEBUG_INFO,
344e01aa904Sopenharmony_ci    /// Contains kernel ABI whitelists
345e01aa904Sopenharmony_ci    KIND_KABI_WHITELISTS,
346e01aa904Sopenharmony_ci    /// Source package.  Contains the source of the binaries in the
347e01aa904Sopenharmony_ci    /// main package.
348e01aa904Sopenharmony_ci    KIND_SRC
349e01aa904Sopenharmony_ci  };
350e01aa904Sopenharmony_ci
351e01aa904Sopenharmony_ciprivate:
352e01aa904Sopenharmony_ci  string				path_;
353e01aa904Sopenharmony_ci  string				extracted_dir_path_;
354e01aa904Sopenharmony_ci  string				common_paths_prefix_;
355e01aa904Sopenharmony_ci  abigail::tools_utils::file_type	type_;
356e01aa904Sopenharmony_ci  kind					kind_;
357e01aa904Sopenharmony_ci  map<string, elf_file_sptr>		path_elf_file_sptr_map_;
358e01aa904Sopenharmony_ci  vector<package_sptr>			debug_info_packages_;
359e01aa904Sopenharmony_ci  package_sptr				devel_package_;
360e01aa904Sopenharmony_ci  package_sptr				kabi_whitelist_package_;
361e01aa904Sopenharmony_ci  vector<string>			elf_file_paths_;
362e01aa904Sopenharmony_ci  set<string>				public_dso_sonames_;
363e01aa904Sopenharmony_ci
364e01aa904Sopenharmony_cipublic:
365e01aa904Sopenharmony_ci  /// Constructor for the @ref package type.
366e01aa904Sopenharmony_ci  ///
367e01aa904Sopenharmony_ci  /// @param path the path to the package.
368e01aa904Sopenharmony_ci  ///
369e01aa904Sopenharmony_ci  /// @parm dir the temporary directory where to extract the content
370e01aa904Sopenharmony_ci  /// of the package.
371e01aa904Sopenharmony_ci  ///
372e01aa904Sopenharmony_ci  /// @param pkg_kind the kind of package.
373e01aa904Sopenharmony_ci  package(const string&			path,
374e01aa904Sopenharmony_ci	  const string&			dir,
375e01aa904Sopenharmony_ci          kind					pkg_kind = package::KIND_MAIN)
376e01aa904Sopenharmony_ci    : path_(path),
377e01aa904Sopenharmony_ci      kind_(pkg_kind)
378e01aa904Sopenharmony_ci  {
379e01aa904Sopenharmony_ci    type_ = guess_file_type(path);
380e01aa904Sopenharmony_ci    if (type_ == abigail::tools_utils::FILE_TYPE_DIR)
381e01aa904Sopenharmony_ci      extracted_dir_path_ = path;
382e01aa904Sopenharmony_ci    else
383e01aa904Sopenharmony_ci      extracted_dir_path_ = extracted_packages_parent_dir() + "/" + dir;
384e01aa904Sopenharmony_ci  }
385e01aa904Sopenharmony_ci
386e01aa904Sopenharmony_ci  /// Getter of the path of the package.
387e01aa904Sopenharmony_ci  ///
388e01aa904Sopenharmony_ci  /// @return the path of the package.
389e01aa904Sopenharmony_ci  const string&
390e01aa904Sopenharmony_ci  path() const
391e01aa904Sopenharmony_ci  {return path_;}
392e01aa904Sopenharmony_ci
393e01aa904Sopenharmony_ci  /// Setter of the path of the package.
394e01aa904Sopenharmony_ci  ///
395e01aa904Sopenharmony_ci  /// @param s the new path.
396e01aa904Sopenharmony_ci  void
397e01aa904Sopenharmony_ci  path(const string& s)
398e01aa904Sopenharmony_ci  {path_ = s;}
399e01aa904Sopenharmony_ci
400e01aa904Sopenharmony_ci  /// Getter of the base name of the package.
401e01aa904Sopenharmony_ci  ///
402e01aa904Sopenharmony_ci  /// @return the base name of the package.
403e01aa904Sopenharmony_ci  string
404e01aa904Sopenharmony_ci  base_name() const
405e01aa904Sopenharmony_ci  {
406e01aa904Sopenharmony_ci    string name;
407e01aa904Sopenharmony_ci    abigail::tools_utils::base_name(path(), name);
408e01aa904Sopenharmony_ci    return name;
409e01aa904Sopenharmony_ci  }
410e01aa904Sopenharmony_ci
411e01aa904Sopenharmony_ci  /// Getter for the path to the root dir where the packages are
412e01aa904Sopenharmony_ci  /// extracted.
413e01aa904Sopenharmony_ci  ///
414e01aa904Sopenharmony_ci  /// @return the path to the root dir where the packages are
415e01aa904Sopenharmony_ci  /// extracted.
416e01aa904Sopenharmony_ci  static const string&
417e01aa904Sopenharmony_ci  extracted_packages_parent_dir();
418e01aa904Sopenharmony_ci
419e01aa904Sopenharmony_ci  /// Getter for the path to the directory where the packages are
420e01aa904Sopenharmony_ci  /// extracted for the current thread.
421e01aa904Sopenharmony_ci  ///
422e01aa904Sopenharmony_ci  /// @return the path to the directory where the packages are
423e01aa904Sopenharmony_ci  /// extracted for the current thread.
424e01aa904Sopenharmony_ci  const string&
425e01aa904Sopenharmony_ci  extracted_dir_path() const
426e01aa904Sopenharmony_ci  {return extracted_dir_path_;}
427e01aa904Sopenharmony_ci
428e01aa904Sopenharmony_ci  /// Setter for the path to the directory where the packages are
429e01aa904Sopenharmony_ci  /// extracted for the current thread.
430e01aa904Sopenharmony_ci  ///
431e01aa904Sopenharmony_ci  /// @param p the new path.
432e01aa904Sopenharmony_ci  void
433e01aa904Sopenharmony_ci  extracted_dir_path(const string& p)
434e01aa904Sopenharmony_ci  {extracted_dir_path_ = p;}
435e01aa904Sopenharmony_ci
436e01aa904Sopenharmony_ci  /// Getter of the the prefix that is common to all the paths of all
437e01aa904Sopenharmony_ci  /// the elements of the package.
438e01aa904Sopenharmony_ci  ///
439e01aa904Sopenharmony_ci  /// @return the common path prefix of package elements.
440e01aa904Sopenharmony_ci  const string&
441e01aa904Sopenharmony_ci  common_paths_prefix() const
442e01aa904Sopenharmony_ci  {return common_paths_prefix_;}
443e01aa904Sopenharmony_ci
444e01aa904Sopenharmony_ci  /// Getter of the the prefix that is common to all the paths of all
445e01aa904Sopenharmony_ci  /// the elements of the package.
446e01aa904Sopenharmony_ci  ///
447e01aa904Sopenharmony_ci  /// @return the common path prefix of package elements.
448e01aa904Sopenharmony_ci  string&
449e01aa904Sopenharmony_ci  common_paths_prefix()
450e01aa904Sopenharmony_ci  {return common_paths_prefix_;}
451e01aa904Sopenharmony_ci
452e01aa904Sopenharmony_ci  /// Setter of the the prefix that is common to all the paths of all
453e01aa904Sopenharmony_ci  /// the elements of the package.
454e01aa904Sopenharmony_ci  ///
455e01aa904Sopenharmony_ci  ///
456e01aa904Sopenharmony_ci  ///@param p the new prefix.
457e01aa904Sopenharmony_ci  void
458e01aa904Sopenharmony_ci  common_paths_prefix(const string& p)
459e01aa904Sopenharmony_ci  {common_paths_prefix_ = p;}
460e01aa904Sopenharmony_ci
461e01aa904Sopenharmony_ci  /// Getter for the file type of the current package.
462e01aa904Sopenharmony_ci  ///
463e01aa904Sopenharmony_ci  /// @return the file type of the current package.
464e01aa904Sopenharmony_ci  abigail::tools_utils::file_type
465e01aa904Sopenharmony_ci  type() const
466e01aa904Sopenharmony_ci  {return type_;}
467e01aa904Sopenharmony_ci
468e01aa904Sopenharmony_ci  /// Setter for the file type of the current package.
469e01aa904Sopenharmony_ci  ///
470e01aa904Sopenharmony_ci  /// @param t the new file type.
471e01aa904Sopenharmony_ci  void type(abigail::tools_utils::file_type t)
472e01aa904Sopenharmony_ci  {type_ = t;}
473e01aa904Sopenharmony_ci
474e01aa904Sopenharmony_ci  /// Get the package kind
475e01aa904Sopenharmony_ci  ///
476e01aa904Sopenharmony_ci  /// @return the package kind
477e01aa904Sopenharmony_ci  kind
478e01aa904Sopenharmony_ci  get_kind() const
479e01aa904Sopenharmony_ci  {return kind_;}
480e01aa904Sopenharmony_ci
481e01aa904Sopenharmony_ci  /// Set the package kind
482e01aa904Sopenharmony_ci  ///
483e01aa904Sopenharmony_ci  /// @param k the package kind.
484e01aa904Sopenharmony_ci  void
485e01aa904Sopenharmony_ci  set_kind(kind k)
486e01aa904Sopenharmony_ci  {kind_ = k;}
487e01aa904Sopenharmony_ci
488e01aa904Sopenharmony_ci  /// Getter for the path <-> elf_file map.
489e01aa904Sopenharmony_ci  ///
490e01aa904Sopenharmony_ci  /// @return the the path <-> elf_file map.
491e01aa904Sopenharmony_ci  const map<string, elf_file_sptr>&
492e01aa904Sopenharmony_ci  path_elf_file_sptr_map() const
493e01aa904Sopenharmony_ci  {return path_elf_file_sptr_map_;}
494e01aa904Sopenharmony_ci
495e01aa904Sopenharmony_ci  /// Getter for the path <-> elf_file map.
496e01aa904Sopenharmony_ci  ///
497e01aa904Sopenharmony_ci  /// @return the the path <-> elf_file map.
498e01aa904Sopenharmony_ci  map<string, elf_file_sptr>&
499e01aa904Sopenharmony_ci  path_elf_file_sptr_map()
500e01aa904Sopenharmony_ci  {return path_elf_file_sptr_map_;}
501e01aa904Sopenharmony_ci
502e01aa904Sopenharmony_ci  /// Getter for the debug info packages associated to the current
503e01aa904Sopenharmony_ci  /// package.
504e01aa904Sopenharmony_ci  ///
505e01aa904Sopenharmony_ci  /// There can indeed be several debug info packages needed for one
506e01aa904Sopenharmony_ci  /// input package, as the debug info for that input package can be
507e01aa904Sopenharmony_ci  /// split across several debuginfo packages.
508e01aa904Sopenharmony_ci  ///
509e01aa904Sopenharmony_ci  /// @return the debug info packages associated to the current
510e01aa904Sopenharmony_ci  /// package.
511e01aa904Sopenharmony_ci  const vector<package_sptr>&
512e01aa904Sopenharmony_ci  debug_info_packages() const
513e01aa904Sopenharmony_ci  {return debug_info_packages_;}
514e01aa904Sopenharmony_ci
515e01aa904Sopenharmony_ci  /// Getter for the debug info packages associated to the current
516e01aa904Sopenharmony_ci  /// package.
517e01aa904Sopenharmony_ci  ///
518e01aa904Sopenharmony_ci  /// There can indeed be several debug info packages needed for one
519e01aa904Sopenharmony_ci  /// input package, as the debug info for that input package can be
520e01aa904Sopenharmony_ci  /// split across several debuginfo packages.
521e01aa904Sopenharmony_ci  ///
522e01aa904Sopenharmony_ci  /// @return the debug info packages associated to the current
523e01aa904Sopenharmony_ci  /// package.
524e01aa904Sopenharmony_ci  vector<package_sptr>&
525e01aa904Sopenharmony_ci  debug_info_packages()
526e01aa904Sopenharmony_ci  {return debug_info_packages_;}
527e01aa904Sopenharmony_ci
528e01aa904Sopenharmony_ci  /// Setter for the debug info packages associated to the current
529e01aa904Sopenharmony_ci  /// package.
530e01aa904Sopenharmony_ci  ///
531e01aa904Sopenharmony_ci  /// There can indeed be several debug info packages needed for one
532e01aa904Sopenharmony_ci  /// input package, as the debug info for that input package can be
533e01aa904Sopenharmony_ci  /// split across several debuginfo packages.
534e01aa904Sopenharmony_ci  ///
535e01aa904Sopenharmony_ci  /// @param p the new debug info package.
536e01aa904Sopenharmony_ci  void
537e01aa904Sopenharmony_ci  debug_info_packages(const vector<package_sptr> &p)
538e01aa904Sopenharmony_ci  {debug_info_packages_ = p;}
539e01aa904Sopenharmony_ci
540e01aa904Sopenharmony_ci  /// Getter for the devel package associated to the current package.
541e01aa904Sopenharmony_ci  ///
542e01aa904Sopenharmony_ci  /// @return the devel package associated to the current package.
543e01aa904Sopenharmony_ci  const package_sptr&
544e01aa904Sopenharmony_ci  devel_package() const
545e01aa904Sopenharmony_ci  {return devel_package_;}
546e01aa904Sopenharmony_ci
547e01aa904Sopenharmony_ci  /// Setter of the devel package associated to the current package.
548e01aa904Sopenharmony_ci  ///
549e01aa904Sopenharmony_ci  /// @param p the new devel package associated to the current package.
550e01aa904Sopenharmony_ci  void
551e01aa904Sopenharmony_ci  devel_package(const package_sptr& p)
552e01aa904Sopenharmony_ci  {devel_package_ = p;}
553e01aa904Sopenharmony_ci
554e01aa904Sopenharmony_ci  /// Getter of the associated kernel abi whitelist package, if any.
555e01aa904Sopenharmony_ci  ///
556e01aa904Sopenharmony_ci  /// @return the associated kernel abi whitelist package.
557e01aa904Sopenharmony_ci  const package_sptr
558e01aa904Sopenharmony_ci  kabi_whitelist_package() const
559e01aa904Sopenharmony_ci  {return kabi_whitelist_package_;}
560e01aa904Sopenharmony_ci
561e01aa904Sopenharmony_ci  /// Setter of the associated kernel abi whitelist package.
562e01aa904Sopenharmony_ci  ///
563e01aa904Sopenharmony_ci  /// @param p the new kernel abi whitelist package.
564e01aa904Sopenharmony_ci  void
565e01aa904Sopenharmony_ci  kabi_whitelist_package(const package_sptr& p)
566e01aa904Sopenharmony_ci  {kabi_whitelist_package_ = p;}
567e01aa904Sopenharmony_ci
568e01aa904Sopenharmony_ci  /// Getter of the path to the elf files of the package.
569e01aa904Sopenharmony_ci  ///
570e01aa904Sopenharmony_ci  /// @return the path tothe elf files of the package.
571e01aa904Sopenharmony_ci  const vector<string>&
572e01aa904Sopenharmony_ci  elf_file_paths() const
573e01aa904Sopenharmony_ci  {return elf_file_paths_;}
574e01aa904Sopenharmony_ci
575e01aa904Sopenharmony_ci  /// Getter of the path to the elf files of the package.
576e01aa904Sopenharmony_ci  ///
577e01aa904Sopenharmony_ci  /// @return the path tothe elf files of the package.
578e01aa904Sopenharmony_ci  vector<string>&
579e01aa904Sopenharmony_ci  elf_file_paths()
580e01aa904Sopenharmony_ci  {return elf_file_paths_;}
581e01aa904Sopenharmony_ci
582e01aa904Sopenharmony_ci  /// Getter of the SONAMEs of the public DSOs carried by this
583e01aa904Sopenharmony_ci  /// package.
584e01aa904Sopenharmony_ci  ///
585e01aa904Sopenharmony_ci  /// This is relevant only if the --private-dso option was *NOT*
586e01aa904Sopenharmony_ci  /// provided.
587e01aa904Sopenharmony_ci  ///
588e01aa904Sopenharmony_ci  /// @return the SONAMEs of the public DSOs carried by this package.
589e01aa904Sopenharmony_ci  const set<string>&
590e01aa904Sopenharmony_ci  public_dso_sonames() const
591e01aa904Sopenharmony_ci  {return public_dso_sonames_;}
592e01aa904Sopenharmony_ci
593e01aa904Sopenharmony_ci  /// Getter of the SONAMEs of the public DSOs carried by this
594e01aa904Sopenharmony_ci  /// package.
595e01aa904Sopenharmony_ci  ///
596e01aa904Sopenharmony_ci  /// This is relevant only if the --private-dso option was *NOT*
597e01aa904Sopenharmony_ci  /// provided.
598e01aa904Sopenharmony_ci  ///
599e01aa904Sopenharmony_ci  /// @return the SONAMEs of the public DSOs carried by this package.
600e01aa904Sopenharmony_ci  set<string>&
601e01aa904Sopenharmony_ci  public_dso_sonames()
602e01aa904Sopenharmony_ci  {return public_dso_sonames_;}
603e01aa904Sopenharmony_ci
604e01aa904Sopenharmony_ci  /// Convert the absolute path of an element of this package into a
605e01aa904Sopenharmony_ci  /// path relative to the root path pointing to this package.
606e01aa904Sopenharmony_ci  ///
607e01aa904Sopenharmony_ci  /// That is, suppose the content of a package named 'pkg' is located
608e01aa904Sopenharmony_ci  /// at /root/path/pkg.  Suppose an element of that package is named
609e01aa904Sopenharmony_ci  /// is at '/root/path/pkg/somewhere/inside/element'.
610e01aa904Sopenharmony_ci  ///
611e01aa904Sopenharmony_ci  /// This function will return the path:
612e01aa904Sopenharmony_ci  /// /pkg/somewhere/inside/element.
613e01aa904Sopenharmony_ci  ///
614e01aa904Sopenharmony_ci  /// @param path the path to consider.
615e01aa904Sopenharmony_ci  ///
616e01aa904Sopenharmony_ci  /// @param converted_path the resulting converted path.  This is set
617e01aa904Sopenharmony_ci  /// iff the function returns true.
618e01aa904Sopenharmony_ci  ///
619e01aa904Sopenharmony_ci  /// @return true if the path could be converted to being relative to
620e01aa904Sopenharmony_ci  /// the extracted directory.
621e01aa904Sopenharmony_ci  bool
622e01aa904Sopenharmony_ci  convert_path_to_relative(const string& path, string& converted_path) const
623e01aa904Sopenharmony_ci  {
624e01aa904Sopenharmony_ci    string root = extracted_dir_path_;
625e01aa904Sopenharmony_ci    real_path(root, root);
626e01aa904Sopenharmony_ci    string p = path;
627e01aa904Sopenharmony_ci    real_path(p, p);
628e01aa904Sopenharmony_ci    return string_suffix(p, root, converted_path);
629e01aa904Sopenharmony_ci  }
630e01aa904Sopenharmony_ci
631e01aa904Sopenharmony_ci  // Convert the absolute path of an element of this package into a
632e01aa904Sopenharmony_ci  // path relative to the prefix common to the paths of all elements
633e01aa904Sopenharmony_ci  // of the package.
634e01aa904Sopenharmony_ci  //
635e01aa904Sopenharmony_ci  // @param path the path to conver.
636e01aa904Sopenharmony_ci  //
637e01aa904Sopenharmony_ci  // @param converted_path the resulting converted path.  This is set
638e01aa904Sopenharmony_ci  // iff the function returns true.
639e01aa904Sopenharmony_ci  //
640e01aa904Sopenharmony_ci  // @return true iff the function could successfully convert @p path
641e01aa904Sopenharmony_ci  // and put the result into @p converted_path.
642e01aa904Sopenharmony_ci  bool
643e01aa904Sopenharmony_ci  convert_path_to_unique_suffix(const string& path,
644e01aa904Sopenharmony_ci				string& converted_path) const
645e01aa904Sopenharmony_ci  {return string_suffix(path, common_paths_prefix(), converted_path);}
646e01aa904Sopenharmony_ci
647e01aa904Sopenharmony_ci  /// Retrieve the set of "interesting" package element paths by
648e01aa904Sopenharmony_ci  /// walking the package.
649e01aa904Sopenharmony_ci  ///
650e01aa904Sopenharmony_ci  /// And then compute the path prefix that is common to all the
651e01aa904Sopenharmony_ci  /// collected elements.
652e01aa904Sopenharmony_ci  ///
653e01aa904Sopenharmony_ci  /// @param the options of this application.
654e01aa904Sopenharmony_ci  void
655e01aa904Sopenharmony_ci  load_elf_file_paths(options& opts)
656e01aa904Sopenharmony_ci  {
657e01aa904Sopenharmony_ci    if (!common_paths_prefix().empty()
658e01aa904Sopenharmony_ci	|| !elf_file_paths().empty())
659e01aa904Sopenharmony_ci      // We have already loaded the elf file paths, don't do it again.
660e01aa904Sopenharmony_ci      return;
661e01aa904Sopenharmony_ci
662e01aa904Sopenharmony_ci    get_interesting_files_under_dir(extracted_dir_path(),
663e01aa904Sopenharmony_ci				    /*file_name_to_look_for=*/"",
664e01aa904Sopenharmony_ci				    opts, elf_file_paths());
665e01aa904Sopenharmony_ci    std::sort(elf_file_paths().begin(), elf_file_paths().end());
666e01aa904Sopenharmony_ci    string common_prefix;
667e01aa904Sopenharmony_ci    sorted_strings_common_prefix(elf_file_paths(), common_paths_prefix());
668e01aa904Sopenharmony_ci  }
669e01aa904Sopenharmony_ci
670e01aa904Sopenharmony_ci  /// Create the path of an ABI file to be associated with a given
671e01aa904Sopenharmony_ci  /// binary.
672e01aa904Sopenharmony_ci  ///
673e01aa904Sopenharmony_ci  /// @param elf_file_path the path to the binary to consider.
674e01aa904Sopenharmony_ci  ///
675e01aa904Sopenharmony_ci  /// @param abi_file_path the resulting ABI file path.  This is set
676e01aa904Sopenharmony_ci  /// iff the function return true.
677e01aa904Sopenharmony_ci  ///
678e01aa904Sopenharmony_ci  /// @return true if the ABI file path could be constructed and the
679e01aa904Sopenharmony_ci  /// directory tree containing it could be created.  In that case,
680e01aa904Sopenharmony_ci  /// the resulting ABI file path is set to the @p abi_file_path
681e01aa904Sopenharmony_ci  /// output parameter.
682e01aa904Sopenharmony_ci  bool
683e01aa904Sopenharmony_ci  create_abi_file_path(const string &elf_file_path,
684e01aa904Sopenharmony_ci		       string &abi_file_path) const
685e01aa904Sopenharmony_ci  {
686e01aa904Sopenharmony_ci    string abi_path, dir, parent;
687e01aa904Sopenharmony_ci    if (!convert_path_to_relative(elf_file_path, abi_path))
688e01aa904Sopenharmony_ci      return false;
689e01aa904Sopenharmony_ci    abi_path = extracted_dir_path() + "/abixml" + abi_path + ".abi";
690e01aa904Sopenharmony_ci    if (!abigail::tools_utils::ensure_parent_dir_created(abi_path))
691e01aa904Sopenharmony_ci      return false;
692e01aa904Sopenharmony_ci    abi_file_path = abi_path;
693e01aa904Sopenharmony_ci    return true;
694e01aa904Sopenharmony_ci  }
695e01aa904Sopenharmony_ci
696e01aa904Sopenharmony_ci  /// Erase the content of the temporary extraction directory that has
697e01aa904Sopenharmony_ci  /// been populated by the @ref extract_package() function;
698e01aa904Sopenharmony_ci  ///
699e01aa904Sopenharmony_ci  /// @param opts the options passed to the current program.
700e01aa904Sopenharmony_ci  void
701e01aa904Sopenharmony_ci  erase_extraction_directory(const options &opts) const
702e01aa904Sopenharmony_ci  {
703e01aa904Sopenharmony_ci    if (type() == abigail::tools_utils::FILE_TYPE_DIR)
704e01aa904Sopenharmony_ci      // If we are comparing two directories, do not erase the
705e01aa904Sopenharmony_ci      // directory as it was provided by the user; it's not a
706e01aa904Sopenharmony_ci      // temporary directory we created ourselves.
707e01aa904Sopenharmony_ci      return;
708e01aa904Sopenharmony_ci
709e01aa904Sopenharmony_ci    if (opts.verbose)
710e01aa904Sopenharmony_ci      emit_prefix("abipkgdiff", cerr)
711e01aa904Sopenharmony_ci	<< "Erasing temporary extraction directory "
712e01aa904Sopenharmony_ci	<< extracted_dir_path()
713e01aa904Sopenharmony_ci	<< " ...";
714e01aa904Sopenharmony_ci
715e01aa904Sopenharmony_ci    string cmd = "rm -rf " + extracted_dir_path();
716e01aa904Sopenharmony_ci    if (system(cmd.c_str()))
717e01aa904Sopenharmony_ci      {
718e01aa904Sopenharmony_ci	if (opts.verbose)
719e01aa904Sopenharmony_ci	  emit_prefix("abipkgdiff", cerr) << " FAILED\n";
720e01aa904Sopenharmony_ci      }
721e01aa904Sopenharmony_ci    else
722e01aa904Sopenharmony_ci      {
723e01aa904Sopenharmony_ci	if (opts.verbose)
724e01aa904Sopenharmony_ci	  emit_prefix("abipkgdiff", cerr) << " DONE\n";
725e01aa904Sopenharmony_ci      }
726e01aa904Sopenharmony_ci  }
727e01aa904Sopenharmony_ci
728e01aa904Sopenharmony_ci  /// Erase the content of all the temporary extraction directories.
729e01aa904Sopenharmony_ci  ///
730e01aa904Sopenharmony_ci  /// @param opts the options passed to the current program.
731e01aa904Sopenharmony_ci  void
732e01aa904Sopenharmony_ci  erase_extraction_directories(const options &opts) const
733e01aa904Sopenharmony_ci  {
734e01aa904Sopenharmony_ci    erase_extraction_directory(opts);
735e01aa904Sopenharmony_ci    if (!debug_info_packages().empty())
736e01aa904Sopenharmony_ci      debug_info_packages().front()->erase_extraction_directory(opts);
737e01aa904Sopenharmony_ci    if (devel_package())
738e01aa904Sopenharmony_ci      devel_package()->erase_extraction_directory(opts);
739e01aa904Sopenharmony_ci    if (kabi_whitelist_package())
740e01aa904Sopenharmony_ci      kabi_whitelist_package()->erase_extraction_directory(opts);
741e01aa904Sopenharmony_ci  }
742e01aa904Sopenharmony_ci}; // end class package.
743e01aa904Sopenharmony_ci
744e01aa904Sopenharmony_ci/// Arguments passed to the comparison tasks.
745e01aa904Sopenharmony_cistruct compare_args
746e01aa904Sopenharmony_ci{
747e01aa904Sopenharmony_ci  const elf_file		elf1;
748e01aa904Sopenharmony_ci  const string&		debug_dir1;
749e01aa904Sopenharmony_ci  const suppressions_type	private_types_suppr1;
750e01aa904Sopenharmony_ci  const elf_file		elf2;
751e01aa904Sopenharmony_ci  const string&		debug_dir2;
752e01aa904Sopenharmony_ci  const suppressions_type	private_types_suppr2;
753e01aa904Sopenharmony_ci  const options&		opts;
754e01aa904Sopenharmony_ci
755e01aa904Sopenharmony_ci  /// Constructor for compare_args, which is used to pass
756e01aa904Sopenharmony_ci  /// information to the comparison threads.
757e01aa904Sopenharmony_ci  ///
758e01aa904Sopenharmony_ci  /// @param elf1 the first elf file to consider.
759e01aa904Sopenharmony_ci  ///
760e01aa904Sopenharmony_ci  /// @param debug_dir1 the directory where the debug info file for @p
761e01aa904Sopenharmony_ci  /// elf1 is stored.
762e01aa904Sopenharmony_ci  ///
763e01aa904Sopenharmony_ci  /// @param elf2 the second elf file to consider.
764e01aa904Sopenharmony_ci  ///
765e01aa904Sopenharmony_ci  /// @param debug_dir2 the directory where the debug info file for @p
766e01aa904Sopenharmony_ci  /// elf2 is stored.
767e01aa904Sopenharmony_ci  ///
768e01aa904Sopenharmony_ci  /// @param opts the options the current program has been called with.
769e01aa904Sopenharmony_ci  compare_args(const elf_file &elf1, const string& debug_dir1,
770e01aa904Sopenharmony_ci	       const suppressions_type& priv_types_suppr1,
771e01aa904Sopenharmony_ci	       const elf_file &elf2, const string& debug_dir2,
772e01aa904Sopenharmony_ci	       const suppressions_type& priv_types_suppr2,
773e01aa904Sopenharmony_ci	       const options& opts)
774e01aa904Sopenharmony_ci    : elf1(elf1), debug_dir1(debug_dir1),
775e01aa904Sopenharmony_ci      private_types_suppr1(priv_types_suppr1),
776e01aa904Sopenharmony_ci      elf2(elf2), debug_dir2(debug_dir2),
777e01aa904Sopenharmony_ci      private_types_suppr2(priv_types_suppr2),
778e01aa904Sopenharmony_ci      opts(opts)
779e01aa904Sopenharmony_ci  {}
780e01aa904Sopenharmony_ci}; // end struct compare_args
781e01aa904Sopenharmony_ci
782e01aa904Sopenharmony_ci/// A convenience typedef for arguments passed to the comparison workers.
783e01aa904Sopenharmony_citypedef shared_ptr<compare_args> compare_args_sptr;
784e01aa904Sopenharmony_ci
785e01aa904Sopenharmony_cistatic bool extract_package_and_map_its_content(const package_sptr &pkg,
786e01aa904Sopenharmony_ci						options &opts);
787e01aa904Sopenharmony_ci
788e01aa904Sopenharmony_ci/// Getter for the path to the parent directory under which packages
789e01aa904Sopenharmony_ci/// extracted by the current thread are placed.
790e01aa904Sopenharmony_ci///
791e01aa904Sopenharmony_ci/// @return the path to the parent directory under which packages
792e01aa904Sopenharmony_ci/// extracted by the current thread are placed.
793e01aa904Sopenharmony_ciconst string&
794e01aa904Sopenharmony_cipackage::extracted_packages_parent_dir()
795e01aa904Sopenharmony_ci{
796e01aa904Sopenharmony_ci  // I tried to declare this in thread-local storage, but GCC 4.4.7
797e01aa904Sopenharmony_ci  // won't let me.  So for now, I am just making it static.  I'll deal
798e01aa904Sopenharmony_ci  // with this later when I have to.
799e01aa904Sopenharmony_ci
800e01aa904Sopenharmony_ci  //static __thread string p;
801e01aa904Sopenharmony_ci  static string p;
802e01aa904Sopenharmony_ci
803e01aa904Sopenharmony_ci  if (p.empty())
804e01aa904Sopenharmony_ci    {
805e01aa904Sopenharmony_ci      const char *cachedir = getenv("XDG_CACHE_HOME");
806e01aa904Sopenharmony_ci
807e01aa904Sopenharmony_ci      if (cachedir != NULL)
808e01aa904Sopenharmony_ci        p = cachedir;
809e01aa904Sopenharmony_ci      else
810e01aa904Sopenharmony_ci        {
811e01aa904Sopenharmony_ci	  const char* s = getenv("HOME");
812e01aa904Sopenharmony_ci	  if (s != NULL)
813e01aa904Sopenharmony_ci	    p = s;
814e01aa904Sopenharmony_ci	  if (p.empty())
815e01aa904Sopenharmony_ci	    {
816e01aa904Sopenharmony_ci	      s = getenv("TMPDIR");
817e01aa904Sopenharmony_ci	      if (s != NULL)
818e01aa904Sopenharmony_ci		p = s;
819e01aa904Sopenharmony_ci	      else
820e01aa904Sopenharmony_ci		p = "/tmp";
821e01aa904Sopenharmony_ci	    }
822e01aa904Sopenharmony_ci	  p += "/.cache/libabigail";
823e01aa904Sopenharmony_ci        }
824e01aa904Sopenharmony_ci
825e01aa904Sopenharmony_ci      // Create the cache directory if it doesn't exist
826e01aa904Sopenharmony_ci      ABG_ASSERT(ensure_dir_path_created(p));
827e01aa904Sopenharmony_ci
828e01aa904Sopenharmony_ci      string libabigail_tmp_dir_template = p;
829e01aa904Sopenharmony_ci      libabigail_tmp_dir_template += "/abipkgdiff-tmp-dir-XXXXXX";
830e01aa904Sopenharmony_ci
831e01aa904Sopenharmony_ci      if (!mkdtemp(const_cast<char*>(libabigail_tmp_dir_template.c_str())))
832e01aa904Sopenharmony_ci	abort();
833e01aa904Sopenharmony_ci
834e01aa904Sopenharmony_ci      p = libabigail_tmp_dir_template;
835e01aa904Sopenharmony_ci    }
836e01aa904Sopenharmony_ci
837e01aa904Sopenharmony_ci  return p;
838e01aa904Sopenharmony_ci}
839e01aa904Sopenharmony_ci
840e01aa904Sopenharmony_ci/// A convenience typedef for shared_ptr of package.
841e01aa904Sopenharmony_citypedef shared_ptr<package> package_sptr;
842e01aa904Sopenharmony_ci
843e01aa904Sopenharmony_ci/// Show the usage of this program.
844e01aa904Sopenharmony_ci///
845e01aa904Sopenharmony_ci/// @param prog_name the name of the program.
846e01aa904Sopenharmony_ci///
847e01aa904Sopenharmony_ci/// @param out the output stream to emit the usage to .
848e01aa904Sopenharmony_cistatic void
849e01aa904Sopenharmony_cidisplay_usage(const string& prog_name, ostream& out)
850e01aa904Sopenharmony_ci{
851e01aa904Sopenharmony_ci  emit_prefix(prog_name, out)
852e01aa904Sopenharmony_ci    << "usage: " << prog_name << " [options] <package1> <package2>\n"
853e01aa904Sopenharmony_ci    << " where options can be:\n"
854e01aa904Sopenharmony_ci    << " --debug-info-pkg1|--d1 <path>  path of debug-info package of package1\n"
855e01aa904Sopenharmony_ci    << " --debug-info-pkg2|--d2 <path>  path of debug-info package of package2\n"
856e01aa904Sopenharmony_ci    << " --devel-pkg1|--devel1 <path>   path of devel package of pakage1\n"
857e01aa904Sopenharmony_ci    << " --devel-pkg2|--devel2 <path>   path of devel package of pakage1\n"
858e01aa904Sopenharmony_ci    << " --drop-private-types  drop private types from "
859e01aa904Sopenharmony_ci    "internal representation\n"
860e01aa904Sopenharmony_ci    << " --no-default-suppression       don't load any default "
861e01aa904Sopenharmony_ci       "suppression specifications\n"
862e01aa904Sopenharmony_ci    << " --suppressions|--suppr <path>  specify supression specification path\n"
863e01aa904Sopenharmony_ci    << " --linux-kernel-abi-whitelist|-w path to a "
864e01aa904Sopenharmony_ci    "linux kernel abi whitelist\n"
865e01aa904Sopenharmony_ci    << " --wp <path>                    path to a linux kernel abi whitelist package\n"
866e01aa904Sopenharmony_ci    << " --keep-tmp-files               don't erase created temporary files\n"
867e01aa904Sopenharmony_ci    << " --dso-only                     compare shared libraries only\n"
868e01aa904Sopenharmony_ci    << " --private-dso                  compare DSOs that are private "
869e01aa904Sopenharmony_ci    "to the package as well\n"
870e01aa904Sopenharmony_ci    << " --leaf-changes-only|-l  only show leaf changes, "
871e01aa904Sopenharmony_ci    "so no change impact analysis (implies --redundant)\n"
872e01aa904Sopenharmony_ci    << " --impacted-interfaces|-i  display interfaces impacted by leaf changes\n"
873e01aa904Sopenharmony_ci    << " --full-impact|-f  when comparing kernel packages, show the "
874e01aa904Sopenharmony_ci    "full impact analysis report rather than the default leaf changes reports\n"
875e01aa904Sopenharmony_ci    << " --non-reachable-types|-t  consider types non reachable"
876e01aa904Sopenharmony_ci    " from public interfaces\n"
877e01aa904Sopenharmony_ci    << "  --exported-interfaces-only  analyze exported interfaces only\n"
878e01aa904Sopenharmony_ci    << "  --allow-non-exported-interfaces  analyze interfaces that "
879e01aa904Sopenharmony_ci    "might not be exported\n"
880e01aa904Sopenharmony_ci    << " --no-linkage-name		do not display linkage names of "
881e01aa904Sopenharmony_ci    "added/removed/changed\n"
882e01aa904Sopenharmony_ci    << " --redundant                    display redundant changes\n"
883e01aa904Sopenharmony_ci    << " --harmless                     display the harmless changes\n"
884e01aa904Sopenharmony_ci    << " --no-show-locs                 do not show location information\n"
885e01aa904Sopenharmony_ci    << " --show-bytes  show size and offsets in bytes\n"
886e01aa904Sopenharmony_ci    << " --show-bits  show size and offsets in bits\n"
887e01aa904Sopenharmony_ci    << " --show-hex  show size and offset in hexadecimal\n"
888e01aa904Sopenharmony_ci    << " --show-dec  show size and offset in decimal\n"
889e01aa904Sopenharmony_ci    << " --no-show-relative-offset-changes  do not show relative"
890e01aa904Sopenharmony_ci    " offset changes\n"
891e01aa904Sopenharmony_ci    << " --no-added-syms                do not display added functions or variables\n"
892e01aa904Sopenharmony_ci    << " --no-unreferenced-symbols do not display changes "
893e01aa904Sopenharmony_ci    "about symbols not referenced by debug info\n"
894e01aa904Sopenharmony_ci    << " --no-added-binaries            do not display added binaries\n"
895e01aa904Sopenharmony_ci    << " --no-abignore                  do not look for *.abignore files\n"
896e01aa904Sopenharmony_ci    << " --no-parallel                  do not execute in parallel\n"
897e01aa904Sopenharmony_ci    << " --fail-no-dbg                  fail if no debug info was found\n"
898e01aa904Sopenharmony_ci    << " --show-identical-binaries      show the names of identical binaries\n"
899e01aa904Sopenharmony_ci    << " --no-leverage-dwarf-factorization  do not use DWZ optimisations to "
900e01aa904Sopenharmony_ci    "speed-up the analysis of the binary\n"
901e01aa904Sopenharmony_ci    << " --no-assume-odr-for-cplusplus  do not assume the ODR to speed-up the"
902e01aa904Sopenharmony_ci    "analysis of the binary\n"
903e01aa904Sopenharmony_ci    << " --verbose                      emit verbose progress messages\n"
904e01aa904Sopenharmony_ci    << " --self-check                   perform a sanity check by comparing "
905e01aa904Sopenharmony_ci    "binaries inside the input package against their ABIXML representation\n"
906e01aa904Sopenharmony_ci#ifdef WITH_CTF
907e01aa904Sopenharmony_ci    << " --ctf                          use CTF instead of DWARF in ELF files\n"
908e01aa904Sopenharmony_ci#endif
909e01aa904Sopenharmony_ci    << " --help|-h                      display this help message\n"
910e01aa904Sopenharmony_ci    << " --version|-v                   display program version information"
911e01aa904Sopenharmony_ci    " and exit\n";
912e01aa904Sopenharmony_ci}
913e01aa904Sopenharmony_ci
914e01aa904Sopenharmony_ci#ifdef WITH_RPM
915e01aa904Sopenharmony_ci
916e01aa904Sopenharmony_ci/// Extract an RPM package.
917e01aa904Sopenharmony_ci///
918e01aa904Sopenharmony_ci/// @param package_path the path to the package to extract.
919e01aa904Sopenharmony_ci///
920e01aa904Sopenharmony_ci/// @param extracted_package_dir_path the path where to extract the
921e01aa904Sopenharmony_ci/// package to.
922e01aa904Sopenharmony_ci///
923e01aa904Sopenharmony_ci/// @param opts the options passed to the current program.
924e01aa904Sopenharmony_ci///
925e01aa904Sopenharmony_ci/// @return true upon successful completion, false otherwise.
926e01aa904Sopenharmony_cistatic bool
927e01aa904Sopenharmony_ciextract_rpm(const string& package_path,
928e01aa904Sopenharmony_ci	    const string& extracted_package_dir_path,
929e01aa904Sopenharmony_ci	    const options &opts)
930e01aa904Sopenharmony_ci{
931e01aa904Sopenharmony_ci  if (opts.verbose)
932e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
933e01aa904Sopenharmony_ci      << "Extracting package "
934e01aa904Sopenharmony_ci      << package_path
935e01aa904Sopenharmony_ci      << " to "
936e01aa904Sopenharmony_ci      << extracted_package_dir_path
937e01aa904Sopenharmony_ci      << " ...";
938e01aa904Sopenharmony_ci
939e01aa904Sopenharmony_ci  string cmd = "test -d " + extracted_package_dir_path
940e01aa904Sopenharmony_ci    + " || mkdir -p " + extracted_package_dir_path + " ; cd " +
941e01aa904Sopenharmony_ci    extracted_package_dir_path + " && rpm2cpio " + package_path +
942e01aa904Sopenharmony_ci    " | cpio -dium --quiet";
943e01aa904Sopenharmony_ci
944e01aa904Sopenharmony_ci  if (system(cmd.c_str()))
945e01aa904Sopenharmony_ci    {
946e01aa904Sopenharmony_ci      if (opts.verbose)
947e01aa904Sopenharmony_ci	emit_prefix("abipkgdiff", cerr) << " FAILED\n";
948e01aa904Sopenharmony_ci      return false;
949e01aa904Sopenharmony_ci    }
950e01aa904Sopenharmony_ci
951e01aa904Sopenharmony_ci  if (opts.verbose)
952e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr) << " DONE\n";
953e01aa904Sopenharmony_ci
954e01aa904Sopenharmony_ci  return true;
955e01aa904Sopenharmony_ci}
956e01aa904Sopenharmony_ci
957e01aa904Sopenharmony_ci#endif // WITH_RPM
958e01aa904Sopenharmony_ci
959e01aa904Sopenharmony_ci#ifdef WITH_DEB
960e01aa904Sopenharmony_ci
961e01aa904Sopenharmony_ci/// Extract a Debian binary package.
962e01aa904Sopenharmony_ci///
963e01aa904Sopenharmony_ci/// @param package_path the path to the package to extract.
964e01aa904Sopenharmony_ci///
965e01aa904Sopenharmony_ci/// @param extracted_package_dir_path the path where to extract the
966e01aa904Sopenharmony_ci/// package to.
967e01aa904Sopenharmony_ci///
968e01aa904Sopenharmony_ci/// @param opts the options passed to the current program.
969e01aa904Sopenharmony_ci///
970e01aa904Sopenharmony_ci/// @return true upon successful completion, false otherwise.
971e01aa904Sopenharmony_cistatic bool
972e01aa904Sopenharmony_ciextract_deb(const string& package_path,
973e01aa904Sopenharmony_ci	    const string& extracted_package_dir_path,
974e01aa904Sopenharmony_ci	    const options &opts)
975e01aa904Sopenharmony_ci{
976e01aa904Sopenharmony_ci  if (opts.verbose)
977e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
978e01aa904Sopenharmony_ci      << "Extracting package "
979e01aa904Sopenharmony_ci      << package_path
980e01aa904Sopenharmony_ci      << " to "
981e01aa904Sopenharmony_ci      << extracted_package_dir_path
982e01aa904Sopenharmony_ci      << " ...\n";
983e01aa904Sopenharmony_ci
984e01aa904Sopenharmony_ci  string cmd = "mkdir -p " + extracted_package_dir_path + " && dpkg -x " +
985e01aa904Sopenharmony_ci    package_path + " " + extracted_package_dir_path;
986e01aa904Sopenharmony_ci
987e01aa904Sopenharmony_ci  if (system(cmd.c_str()))
988e01aa904Sopenharmony_ci    {
989e01aa904Sopenharmony_ci      if (opts.verbose)
990e01aa904Sopenharmony_ci	emit_prefix("abipkgdiff", cerr) << " FAILED\n";
991e01aa904Sopenharmony_ci      return false;
992e01aa904Sopenharmony_ci    }
993e01aa904Sopenharmony_ci
994e01aa904Sopenharmony_ci  if (opts.verbose)
995e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr) << " DONE\n";
996e01aa904Sopenharmony_ci
997e01aa904Sopenharmony_ci  return true;
998e01aa904Sopenharmony_ci}
999e01aa904Sopenharmony_ci
1000e01aa904Sopenharmony_ci#endif // WITH_DEB
1001e01aa904Sopenharmony_ci
1002e01aa904Sopenharmony_ci#ifdef WITH_TAR
1003e01aa904Sopenharmony_ci
1004e01aa904Sopenharmony_ci/// Extract a GNU Tar archive.
1005e01aa904Sopenharmony_ci///
1006e01aa904Sopenharmony_ci/// @param package_path the path to the archive to extract.
1007e01aa904Sopenharmony_ci///
1008e01aa904Sopenharmony_ci/// @param extracted_package_dir_path the path where to extract the
1009e01aa904Sopenharmony_ci/// archive to.
1010e01aa904Sopenharmony_ci///
1011e01aa904Sopenharmony_ci/// @param opts the options passed to the current program.
1012e01aa904Sopenharmony_ci///
1013e01aa904Sopenharmony_ci/// @return true upon successful completion, false otherwise.
1014e01aa904Sopenharmony_cistatic bool
1015e01aa904Sopenharmony_ciextract_tar(const string& package_path,
1016e01aa904Sopenharmony_ci	    const string& extracted_package_dir_path,
1017e01aa904Sopenharmony_ci	    const options &opts)
1018e01aa904Sopenharmony_ci{
1019e01aa904Sopenharmony_ci  if (opts.verbose)
1020e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
1021e01aa904Sopenharmony_ci      << "Extracting tar archive "
1022e01aa904Sopenharmony_ci      << package_path
1023e01aa904Sopenharmony_ci      << " to "
1024e01aa904Sopenharmony_ci      << extracted_package_dir_path
1025e01aa904Sopenharmony_ci      << " ...";
1026e01aa904Sopenharmony_ci
1027e01aa904Sopenharmony_ci  string cmd = "test -d " +
1028e01aa904Sopenharmony_ci    extracted_package_dir_path +
1029e01aa904Sopenharmony_ci    " && rm -rf " + extracted_package_dir_path;
1030e01aa904Sopenharmony_ci
1031e01aa904Sopenharmony_ci  if (system(cmd.c_str()))
1032e01aa904Sopenharmony_ci    {
1033e01aa904Sopenharmony_ci      if (opts.verbose)
1034e01aa904Sopenharmony_ci	emit_prefix("abipkgdiff", cerr) << "command " << cmd << " FAILED\n";
1035e01aa904Sopenharmony_ci    }
1036e01aa904Sopenharmony_ci
1037e01aa904Sopenharmony_ci  cmd = "mkdir -p " + extracted_package_dir_path + " && cd " +
1038e01aa904Sopenharmony_ci    extracted_package_dir_path + " && tar -xf " + package_path;
1039e01aa904Sopenharmony_ci
1040e01aa904Sopenharmony_ci  if (system(cmd.c_str()))
1041e01aa904Sopenharmony_ci    {
1042e01aa904Sopenharmony_ci      if (opts.verbose)
1043e01aa904Sopenharmony_ci	emit_prefix("abipkgdiff", cerr) << " FAILED\n";
1044e01aa904Sopenharmony_ci      return false;
1045e01aa904Sopenharmony_ci    }
1046e01aa904Sopenharmony_ci
1047e01aa904Sopenharmony_ci  if (opts.verbose)
1048e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr) << " DONE\n";
1049e01aa904Sopenharmony_ci
1050e01aa904Sopenharmony_ci  return true;
1051e01aa904Sopenharmony_ci}
1052e01aa904Sopenharmony_ci
1053e01aa904Sopenharmony_ci#endif // WITH_TAR
1054e01aa904Sopenharmony_ci
1055e01aa904Sopenharmony_ci/// Erase the temporary directories created for the extraction of two
1056e01aa904Sopenharmony_ci/// packages.
1057e01aa904Sopenharmony_ci///
1058e01aa904Sopenharmony_ci/// @param first_package the first package to consider.
1059e01aa904Sopenharmony_ci///
1060e01aa904Sopenharmony_ci/// @param opts the options passed to the current program.
1061e01aa904Sopenharmony_ci///
1062e01aa904Sopenharmony_ci/// @param second_package the second package to consider.
1063e01aa904Sopenharmony_cistatic void
1064e01aa904Sopenharmony_cierase_created_temporary_directories(const package& first_package,
1065e01aa904Sopenharmony_ci				    const package& second_package,
1066e01aa904Sopenharmony_ci				    const options &opts)
1067e01aa904Sopenharmony_ci{
1068e01aa904Sopenharmony_ci  first_package.erase_extraction_directories(opts);
1069e01aa904Sopenharmony_ci  second_package.erase_extraction_directories(opts);
1070e01aa904Sopenharmony_ci}
1071e01aa904Sopenharmony_ci
1072e01aa904Sopenharmony_ci/// Erase the root of all the temporary directories created by the
1073e01aa904Sopenharmony_ci/// current thread.
1074e01aa904Sopenharmony_cistatic void
1075e01aa904Sopenharmony_cierase_created_temporary_directories_parent(const options &opts)
1076e01aa904Sopenharmony_ci{
1077e01aa904Sopenharmony_ci  if (opts.verbose)
1078e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
1079e01aa904Sopenharmony_ci      << "Erasing temporary extraction parent directory "
1080e01aa904Sopenharmony_ci      << package::extracted_packages_parent_dir()
1081e01aa904Sopenharmony_ci      << " ...";
1082e01aa904Sopenharmony_ci
1083e01aa904Sopenharmony_ci  string cmd = "rm -rf " + package::extracted_packages_parent_dir();
1084e01aa904Sopenharmony_ci  if (system(cmd.c_str()))
1085e01aa904Sopenharmony_ci    {
1086e01aa904Sopenharmony_ci      if (opts.verbose)
1087e01aa904Sopenharmony_ci	emit_prefix("abipkgdiff", cerr) << "FAILED\n";
1088e01aa904Sopenharmony_ci    }
1089e01aa904Sopenharmony_ci  else
1090e01aa904Sopenharmony_ci    {
1091e01aa904Sopenharmony_ci      if (opts.verbose)
1092e01aa904Sopenharmony_ci	emit_prefix("abipkgdiff", cerr) << "DONE\n";
1093e01aa904Sopenharmony_ci    }
1094e01aa904Sopenharmony_ci}
1095e01aa904Sopenharmony_ci
1096e01aa904Sopenharmony_ci/// Extract the content of a package.
1097e01aa904Sopenharmony_ci///
1098e01aa904Sopenharmony_ci/// @param package the package we are looking at.
1099e01aa904Sopenharmony_ci///
1100e01aa904Sopenharmony_ci/// @param opts the options passed to the current program.
1101e01aa904Sopenharmony_cistatic bool
1102e01aa904Sopenharmony_ciextract_package(const package& package,
1103e01aa904Sopenharmony_ci		const options &opts)
1104e01aa904Sopenharmony_ci{
1105e01aa904Sopenharmony_ci  switch(package.type())
1106e01aa904Sopenharmony_ci    {
1107e01aa904Sopenharmony_ci    case abigail::tools_utils::FILE_TYPE_RPM:
1108e01aa904Sopenharmony_ci#ifdef WITH_RPM
1109e01aa904Sopenharmony_ci      if (!extract_rpm(package.path(), package.extracted_dir_path(), opts))
1110e01aa904Sopenharmony_ci        {
1111e01aa904Sopenharmony_ci          emit_prefix("abipkgdiff", cerr)
1112e01aa904Sopenharmony_ci	    << "Error while extracting package " << package.path() << "\n";
1113e01aa904Sopenharmony_ci          return false;
1114e01aa904Sopenharmony_ci        }
1115e01aa904Sopenharmony_ci      return true;
1116e01aa904Sopenharmony_ci#else
1117e01aa904Sopenharmony_ci      emit_prefix("abipkgdiff", cerr)
1118e01aa904Sopenharmony_ci	<< "Support for rpm hasn't been enabled.  Please consider "
1119e01aa904Sopenharmony_ci      "enabling it at package configure time\n";
1120e01aa904Sopenharmony_ci      return false;
1121e01aa904Sopenharmony_ci#endif // WITH_RPM
1122e01aa904Sopenharmony_ci      break;
1123e01aa904Sopenharmony_ci    case abigail::tools_utils::FILE_TYPE_DEB:
1124e01aa904Sopenharmony_ci#ifdef WITH_DEB
1125e01aa904Sopenharmony_ci      if (!extract_deb(package.path(), package.extracted_dir_path(), opts))
1126e01aa904Sopenharmony_ci        {
1127e01aa904Sopenharmony_ci          emit_prefix("abipkgdiff", cerr)
1128e01aa904Sopenharmony_ci	    << "Error while extracting package" << package.path() << "\n";
1129e01aa904Sopenharmony_ci          return false;
1130e01aa904Sopenharmony_ci        }
1131e01aa904Sopenharmony_ci      return true;
1132e01aa904Sopenharmony_ci#else
1133e01aa904Sopenharmony_ci      emit_prefix("abipkgdiff", cerr)
1134e01aa904Sopenharmony_ci	<< "Support for deb hasn't been enabled.  Please consider "
1135e01aa904Sopenharmony_ci	"enabling it at package configure time\n";
1136e01aa904Sopenharmony_ci      return false;
1137e01aa904Sopenharmony_ci#endif // WITH_DEB
1138e01aa904Sopenharmony_ci      break;
1139e01aa904Sopenharmony_ci
1140e01aa904Sopenharmony_ci    case  abigail::tools_utils::FILE_TYPE_DIR:
1141e01aa904Sopenharmony_ci      // The input package is just a directory that contains binaries,
1142e01aa904Sopenharmony_ci      // there is nothing to extract.
1143e01aa904Sopenharmony_ci      break;
1144e01aa904Sopenharmony_ci
1145e01aa904Sopenharmony_ci    case abigail::tools_utils::FILE_TYPE_TAR:
1146e01aa904Sopenharmony_ci#ifdef WITH_TAR
1147e01aa904Sopenharmony_ci      if (!extract_tar(package.path(), package.extracted_dir_path(), opts))
1148e01aa904Sopenharmony_ci        {
1149e01aa904Sopenharmony_ci          emit_prefix("abipkgdiff", cerr)
1150e01aa904Sopenharmony_ci	    << "Error while extracting GNU tar archive "
1151e01aa904Sopenharmony_ci	    << package.path() << "\n";
1152e01aa904Sopenharmony_ci          return false;
1153e01aa904Sopenharmony_ci        }
1154e01aa904Sopenharmony_ci      return true;
1155e01aa904Sopenharmony_ci#else
1156e01aa904Sopenharmony_ci      emit_prefix("abipkgdiff", cerr)
1157e01aa904Sopenharmony_ci	<< "Support for GNU tar hasn't been enabled.  Please consider "
1158e01aa904Sopenharmony_ci	"enabling it at package configure time\n";
1159e01aa904Sopenharmony_ci      return false;
1160e01aa904Sopenharmony_ci#endif // WITH_TAR
1161e01aa904Sopenharmony_ci      break;
1162e01aa904Sopenharmony_ci
1163e01aa904Sopenharmony_ci    default:
1164e01aa904Sopenharmony_ci      return false;
1165e01aa904Sopenharmony_ci    }
1166e01aa904Sopenharmony_ci  return true;
1167e01aa904Sopenharmony_ci}
1168e01aa904Sopenharmony_ci
1169e01aa904Sopenharmony_ci/// Check that the suppression specification files supplied are
1170e01aa904Sopenharmony_ci/// present.  If not, emit an error on stderr.
1171e01aa904Sopenharmony_ci///
1172e01aa904Sopenharmony_ci/// @param opts the options instance to use.
1173e01aa904Sopenharmony_ci///
1174e01aa904Sopenharmony_ci/// @return true if all suppression specification files are present,
1175e01aa904Sopenharmony_ci/// false otherwise.
1176e01aa904Sopenharmony_cistatic bool
1177e01aa904Sopenharmony_cimaybe_check_suppression_files(const options& opts)
1178e01aa904Sopenharmony_ci{
1179e01aa904Sopenharmony_ci  for (vector<string>::const_iterator i = opts.suppression_paths.begin();
1180e01aa904Sopenharmony_ci       i != opts.suppression_paths.end();
1181e01aa904Sopenharmony_ci       ++i)
1182e01aa904Sopenharmony_ci    if (!check_file(*i, cerr, opts.prog_name))
1183e01aa904Sopenharmony_ci      return false;
1184e01aa904Sopenharmony_ci
1185e01aa904Sopenharmony_ci  for (vector<string>::const_iterator i =
1186e01aa904Sopenharmony_ci	 opts.kabi_whitelist_paths.begin();
1187e01aa904Sopenharmony_ci       i != opts.kabi_whitelist_paths.end();
1188e01aa904Sopenharmony_ci       ++i)
1189e01aa904Sopenharmony_ci    if (!check_file(*i, cerr, "abidiff"))
1190e01aa904Sopenharmony_ci      return false;
1191e01aa904Sopenharmony_ci
1192e01aa904Sopenharmony_ci  return true;
1193e01aa904Sopenharmony_ci}
1194e01aa904Sopenharmony_ci
1195e01aa904Sopenharmony_ci/// Update the diff context from the @ref options data structure.
1196e01aa904Sopenharmony_ci///
1197e01aa904Sopenharmony_ci/// @param ctxt the diff context to update.
1198e01aa904Sopenharmony_ci///
1199e01aa904Sopenharmony_ci/// @param opts the instance of @ref options to consider.
1200e01aa904Sopenharmony_cistatic void
1201e01aa904Sopenharmony_ciset_diff_context_from_opts(diff_context_sptr ctxt,
1202e01aa904Sopenharmony_ci			   const options& opts)
1203e01aa904Sopenharmony_ci{
1204e01aa904Sopenharmony_ci  ctxt->default_output_stream(&cout);
1205e01aa904Sopenharmony_ci  ctxt->error_output_stream(&cerr);
1206e01aa904Sopenharmony_ci  // See comment in abidiff.cc's set_diff_context_from_opts.
1207e01aa904Sopenharmony_ci  ctxt->show_redundant_changes(opts.show_redundant_changes
1208e01aa904Sopenharmony_ci                               || opts.leaf_changes_only);
1209e01aa904Sopenharmony_ci  ctxt->show_leaf_changes_only(opts.leaf_changes_only);
1210e01aa904Sopenharmony_ci  ctxt->show_impacted_interfaces(opts.show_impacted_interfaces);
1211e01aa904Sopenharmony_ci  ctxt->show_unreachable_types(opts.show_all_types);
1212e01aa904Sopenharmony_ci  ctxt->show_hex_values(opts.show_hexadecimal_values);
1213e01aa904Sopenharmony_ci  ctxt->show_offsets_sizes_in_bits(opts.show_offsets_sizes_in_bits);
1214e01aa904Sopenharmony_ci  ctxt->show_relative_offset_changes(opts.show_relative_offset_changes);
1215e01aa904Sopenharmony_ci  ctxt->show_locs(opts.show_locs);
1216e01aa904Sopenharmony_ci  ctxt->show_linkage_names(opts.show_linkage_names);
1217e01aa904Sopenharmony_ci  ctxt->show_added_fns(opts.show_added_syms);
1218e01aa904Sopenharmony_ci  ctxt->show_added_vars(opts.show_added_syms);
1219e01aa904Sopenharmony_ci  ctxt->show_added_symbols_unreferenced_by_debug_info
1220e01aa904Sopenharmony_ci    (opts.show_added_syms);
1221e01aa904Sopenharmony_ci  ctxt->show_symbols_unreferenced_by_debug_info
1222e01aa904Sopenharmony_ci    (opts.show_symbols_not_referenced_by_debug_info);
1223e01aa904Sopenharmony_ci
1224e01aa904Sopenharmony_ci  if (!opts.show_harmless_changes)
1225e01aa904Sopenharmony_ci    ctxt->switch_categories_off(get_default_harmless_categories_bitmap());
1226e01aa904Sopenharmony_ci
1227e01aa904Sopenharmony_ci  suppressions_type supprs;
1228e01aa904Sopenharmony_ci  for (vector<string>::const_iterator i = opts.suppression_paths.begin();
1229e01aa904Sopenharmony_ci       i != opts.suppression_paths.end();
1230e01aa904Sopenharmony_ci       ++i)
1231e01aa904Sopenharmony_ci    read_suppressions(*i, supprs);
1232e01aa904Sopenharmony_ci  ctxt->add_suppressions(supprs);
1233e01aa904Sopenharmony_ci}
1234e01aa904Sopenharmony_ci
1235e01aa904Sopenharmony_ci/// Set a bunch of tunable buttons on the ELF-based reader from the
1236e01aa904Sopenharmony_ci/// command-line options.
1237e01aa904Sopenharmony_ci///
1238e01aa904Sopenharmony_ci/// @param rdr the reader to tune.
1239e01aa904Sopenharmony_ci///
1240e01aa904Sopenharmony_ci/// @param opts the command line options.
1241e01aa904Sopenharmony_cistatic void
1242e01aa904Sopenharmony_ciset_generic_options(abigail::elf_based_reader& rdr, const options& opts)
1243e01aa904Sopenharmony_ci{
1244e01aa904Sopenharmony_ci  if (!opts.kabi_suppressions.empty())
1245e01aa904Sopenharmony_ci    rdr.add_suppressions(opts.kabi_suppressions);
1246e01aa904Sopenharmony_ci
1247e01aa904Sopenharmony_ci  rdr.options().leverage_dwarf_factorization =
1248e01aa904Sopenharmony_ci    opts.leverage_dwarf_factorization;
1249e01aa904Sopenharmony_ci  rdr.options().assume_odr_for_cplusplus =
1250e01aa904Sopenharmony_ci    opts.assume_odr_for_cplusplus;
1251e01aa904Sopenharmony_ci}
1252e01aa904Sopenharmony_ci
1253e01aa904Sopenharmony_ci/// Compare the ABI two elf files, using their associated debug info.
1254e01aa904Sopenharmony_ci///
1255e01aa904Sopenharmony_ci/// The result of the comparison is emitted to standard output.
1256e01aa904Sopenharmony_ci///
1257e01aa904Sopenharmony_ci/// @param elf1 the first elf file to consider.
1258e01aa904Sopenharmony_ci///
1259e01aa904Sopenharmony_ci/// @param debug_dir1 the directory where the debug info file for @p
1260e01aa904Sopenharmony_ci/// elf1 is stored.
1261e01aa904Sopenharmony_ci/// The result of the comparison is saved to a global corpus map.
1262e01aa904Sopenharmony_ci///
1263e01aa904Sopenharmony_ci/// @param elf2 the second eld file to consider.
1264e01aa904Sopenharmony_ci/// @args the list of argument sets used for comparison
1265e01aa904Sopenharmony_ci///
1266e01aa904Sopenharmony_ci/// @param debug_dir2 the directory where the debug info file for @p
1267e01aa904Sopenharmony_ci/// elf2 is stored.
1268e01aa904Sopenharmony_ci///
1269e01aa904Sopenharmony_ci/// @param opts the options the current program has been called with.
1270e01aa904Sopenharmony_ci///
1271e01aa904Sopenharmony_ci/// @param env the environment encapsulating the entire comparison.
1272e01aa904Sopenharmony_ci///
1273e01aa904Sopenharmony_ci/// @param diff the shared pointer to be set to the result of the comparison.
1274e01aa904Sopenharmony_ci///
1275e01aa904Sopenharmony_ci/// @param detailed_error_status is this pointer is non-null and if
1276e01aa904Sopenharmony_ci/// the function returns ABIDIFF_ERROR, then the function sets the
1277e01aa904Sopenharmony_ci/// pointed-to parameter to the abigail::fe_iface::status value
1278e01aa904Sopenharmony_ci/// that gives details about the rror.
1279e01aa904Sopenharmony_ci///
1280e01aa904Sopenharmony_ci/// @return the status of the comparison.
1281e01aa904Sopenharmony_cistatic abidiff_status
1282e01aa904Sopenharmony_cicompare(const elf_file&		elf1,
1283e01aa904Sopenharmony_ci	const string&			debug_dir1,
1284e01aa904Sopenharmony_ci	const suppressions_type&	priv_types_supprs1,
1285e01aa904Sopenharmony_ci	const elf_file&		elf2,
1286e01aa904Sopenharmony_ci	const string&			debug_dir2,
1287e01aa904Sopenharmony_ci	const suppressions_type&	priv_types_supprs2,
1288e01aa904Sopenharmony_ci	const options&			opts,
1289e01aa904Sopenharmony_ci	abigail::ir::environment&	env,
1290e01aa904Sopenharmony_ci	corpus_diff_sptr&		diff,
1291e01aa904Sopenharmony_ci	diff_context_sptr&		ctxt,
1292e01aa904Sopenharmony_ci	abigail::fe_iface::status*	detailed_error_status = 0)
1293e01aa904Sopenharmony_ci{
1294e01aa904Sopenharmony_ci  char *di_dir1 = (char*) debug_dir1.c_str(),
1295e01aa904Sopenharmony_ci	*di_dir2 = (char*) debug_dir2.c_str();
1296e01aa904Sopenharmony_ci
1297e01aa904Sopenharmony_ci  vector<char**> di_dirs1, di_dirs2;
1298e01aa904Sopenharmony_ci  di_dirs1.push_back(&di_dir1);
1299e01aa904Sopenharmony_ci  di_dirs2.push_back(&di_dir2);
1300e01aa904Sopenharmony_ci
1301e01aa904Sopenharmony_ci  if (opts.verbose)
1302e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
1303e01aa904Sopenharmony_ci      << "Comparing the ABIs of file "
1304e01aa904Sopenharmony_ci      << elf1.path
1305e01aa904Sopenharmony_ci      << " and "
1306e01aa904Sopenharmony_ci      << elf2.path
1307e01aa904Sopenharmony_ci      << "...\n";
1308e01aa904Sopenharmony_ci
1309e01aa904Sopenharmony_ci  abigail::fe_iface::status c1_status = abigail::fe_iface::STATUS_OK,
1310e01aa904Sopenharmony_ci    c2_status = abigail::fe_iface::STATUS_OK;
1311e01aa904Sopenharmony_ci
1312e01aa904Sopenharmony_ci  ctxt.reset(new diff_context);
1313e01aa904Sopenharmony_ci  set_diff_context_from_opts(ctxt, opts);
1314e01aa904Sopenharmony_ci  suppressions_type& supprs = ctxt->suppressions();
1315e01aa904Sopenharmony_ci  bool files_suppressed = (file_is_suppressed(elf1.path, supprs)
1316e01aa904Sopenharmony_ci			   ||file_is_suppressed(elf2.path, supprs));
1317e01aa904Sopenharmony_ci
1318e01aa904Sopenharmony_ci  if (files_suppressed)
1319e01aa904Sopenharmony_ci    {
1320e01aa904Sopenharmony_ci      if (opts.verbose)
1321e01aa904Sopenharmony_ci	emit_prefix("abipkgdiff", cerr)
1322e01aa904Sopenharmony_ci	  << "  input file "
1323e01aa904Sopenharmony_ci	  << elf1.path << " or " << elf2.path
1324e01aa904Sopenharmony_ci	  << " has been suppressed by a suppression specification.\n"
1325e01aa904Sopenharmony_ci	  << " Not reading any of them\n";
1326e01aa904Sopenharmony_ci      return abigail::tools_utils::ABIDIFF_OK;
1327e01aa904Sopenharmony_ci    }
1328e01aa904Sopenharmony_ci
1329e01aa904Sopenharmony_ci  // Add the first private type suppressions set to the set of
1330e01aa904Sopenharmony_ci  // suppressions.
1331e01aa904Sopenharmony_ci  for (suppressions_type::const_iterator i = priv_types_supprs1.begin();
1332e01aa904Sopenharmony_ci       i != priv_types_supprs1.end();
1333e01aa904Sopenharmony_ci       ++i)
1334e01aa904Sopenharmony_ci    supprs.push_back(*i);
1335e01aa904Sopenharmony_ci
1336e01aa904Sopenharmony_ci  // Add the second private type suppressions set to the set of
1337e01aa904Sopenharmony_ci  // suppressions.
1338e01aa904Sopenharmony_ci  for (suppressions_type::const_iterator i = priv_types_supprs2.begin();
1339e01aa904Sopenharmony_ci       i != priv_types_supprs2.end();
1340e01aa904Sopenharmony_ci       ++i)
1341e01aa904Sopenharmony_ci    supprs.push_back(*i);
1342e01aa904Sopenharmony_ci
1343e01aa904Sopenharmony_ci  if (opts.verbose)
1344e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
1345e01aa904Sopenharmony_ci      << "Reading file "
1346e01aa904Sopenharmony_ci      << elf1.path
1347e01aa904Sopenharmony_ci      << " ...\n";
1348e01aa904Sopenharmony_ci
1349e01aa904Sopenharmony_ci  abigail::elf_based_reader_sptr reader;
1350e01aa904Sopenharmony_ci  corpus_sptr corpus1;
1351e01aa904Sopenharmony_ci  {
1352e01aa904Sopenharmony_ci    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
1353e01aa904Sopenharmony_ci#ifdef WITH_CTF
1354e01aa904Sopenharmony_ci    if (opts.use_ctf)
1355e01aa904Sopenharmony_ci      requested_fe_kind = corpus::CTF_ORIGIN;
1356e01aa904Sopenharmony_ci#endif
1357e01aa904Sopenharmony_ci    abigail::elf_based_reader_sptr reader =
1358e01aa904Sopenharmony_ci      create_best_elf_based_reader(elf1.path,
1359e01aa904Sopenharmony_ci				   di_dirs1,
1360e01aa904Sopenharmony_ci				   env, requested_fe_kind,
1361e01aa904Sopenharmony_ci				   opts.show_all_types);
1362e01aa904Sopenharmony_ci    ABG_ASSERT(reader);
1363e01aa904Sopenharmony_ci
1364e01aa904Sopenharmony_ci    reader->add_suppressions(priv_types_supprs1);
1365e01aa904Sopenharmony_ci    set_generic_options(*reader, opts);
1366e01aa904Sopenharmony_ci
1367e01aa904Sopenharmony_ci    corpus1 = reader->read_corpus(c1_status);
1368e01aa904Sopenharmony_ci
1369e01aa904Sopenharmony_ci    bool bail_out = false;
1370e01aa904Sopenharmony_ci    if (!(c1_status & abigail::fe_iface::STATUS_OK))
1371e01aa904Sopenharmony_ci      {
1372e01aa904Sopenharmony_ci	if (opts.verbose)
1373e01aa904Sopenharmony_ci	  emit_prefix("abipkgdiff", cerr)
1374e01aa904Sopenharmony_ci	    << "Could not read file '"
1375e01aa904Sopenharmony_ci	    << elf1.path
1376e01aa904Sopenharmony_ci	    << "' properly\n";
1377e01aa904Sopenharmony_ci
1378e01aa904Sopenharmony_ci	if (detailed_error_status)
1379e01aa904Sopenharmony_ci	  *detailed_error_status = c1_status;
1380e01aa904Sopenharmony_ci
1381e01aa904Sopenharmony_ci	bail_out = true;
1382e01aa904Sopenharmony_ci      }
1383e01aa904Sopenharmony_ci
1384e01aa904Sopenharmony_ci    if (opts.fail_if_no_debug_info)
1385e01aa904Sopenharmony_ci      {
1386e01aa904Sopenharmony_ci	bool debug_info_error = false;
1387e01aa904Sopenharmony_ci	if (c1_status & abigail::fe_iface::STATUS_DEBUG_INFO_NOT_FOUND)
1388e01aa904Sopenharmony_ci	  {
1389e01aa904Sopenharmony_ci	    if (opts.verbose)
1390e01aa904Sopenharmony_ci	      emit_prefix("abipkgdiff", cerr)
1391e01aa904Sopenharmony_ci		<< "while reading file" << elf1.path << "\n";
1392e01aa904Sopenharmony_ci
1393e01aa904Sopenharmony_ci	    emit_prefix("abipkgdiff", cerr) << "Could not find debug info file";
1394e01aa904Sopenharmony_ci	    if (di_dir1 && strcmp(di_dir1, ""))
1395e01aa904Sopenharmony_ci	      cerr << " under " << di_dir1 << "\n";
1396e01aa904Sopenharmony_ci	    else
1397e01aa904Sopenharmony_ci	       cerr << "\n";
1398e01aa904Sopenharmony_ci
1399e01aa904Sopenharmony_ci	    if (detailed_error_status)
1400e01aa904Sopenharmony_ci	      *detailed_error_status = c1_status;
1401e01aa904Sopenharmony_ci	    debug_info_error = true;
1402e01aa904Sopenharmony_ci	  }
1403e01aa904Sopenharmony_ci
1404e01aa904Sopenharmony_ci	if (c1_status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
1405e01aa904Sopenharmony_ci	  {
1406e01aa904Sopenharmony_ci	    if (opts.verbose)
1407e01aa904Sopenharmony_ci	      emit_prefix("abipkgdiff", cerr)
1408e01aa904Sopenharmony_ci		<< "while reading file" << elf1.path << "\n";
1409e01aa904Sopenharmony_ci
1410e01aa904Sopenharmony_ci	    emit_prefix("abipkgdiff", cerr)
1411e01aa904Sopenharmony_ci	      << "Could not find alternate debug info file";
1412e01aa904Sopenharmony_ci	    string alt_di_path;
1413e01aa904Sopenharmony_ci#ifdef WITH_CTF
1414e01aa904Sopenharmony_ci            if (opts.use_ctf)
1415e01aa904Sopenharmony_ci              ;
1416e01aa904Sopenharmony_ci            else
1417e01aa904Sopenharmony_ci#endif
1418e01aa904Sopenharmony_ci	      reader->refers_to_alt_debug_info(alt_di_path);
1419e01aa904Sopenharmony_ci	    if (!alt_di_path.empty())
1420e01aa904Sopenharmony_ci	      cerr << ": " << alt_di_path << "\n";
1421e01aa904Sopenharmony_ci	    else
1422e01aa904Sopenharmony_ci	      cerr << "\n";
1423e01aa904Sopenharmony_ci
1424e01aa904Sopenharmony_ci	    if (detailed_error_status)
1425e01aa904Sopenharmony_ci	      *detailed_error_status = c1_status;
1426e01aa904Sopenharmony_ci	    debug_info_error = true;
1427e01aa904Sopenharmony_ci	  }
1428e01aa904Sopenharmony_ci
1429e01aa904Sopenharmony_ci	if (debug_info_error)
1430e01aa904Sopenharmony_ci	  bail_out = true;
1431e01aa904Sopenharmony_ci      }
1432e01aa904Sopenharmony_ci
1433e01aa904Sopenharmony_ci    if (bail_out)
1434e01aa904Sopenharmony_ci      return abigail::tools_utils::ABIDIFF_ERROR;
1435e01aa904Sopenharmony_ci  }
1436e01aa904Sopenharmony_ci
1437e01aa904Sopenharmony_ci  if (opts.verbose)
1438e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
1439e01aa904Sopenharmony_ci      << "DONE reading file "
1440e01aa904Sopenharmony_ci      << elf1.path
1441e01aa904Sopenharmony_ci      << "\n";
1442e01aa904Sopenharmony_ci
1443e01aa904Sopenharmony_ci  if (opts.verbose)
1444e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
1445e01aa904Sopenharmony_ci      << "Reading file "
1446e01aa904Sopenharmony_ci      << elf2.path
1447e01aa904Sopenharmony_ci      << " ...\n";
1448e01aa904Sopenharmony_ci
1449e01aa904Sopenharmony_ci  corpus_sptr corpus2;
1450e01aa904Sopenharmony_ci  {
1451e01aa904Sopenharmony_ci    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
1452e01aa904Sopenharmony_ci#ifdef WITH_CTF
1453e01aa904Sopenharmony_ci    if (opts.use_ctf)
1454e01aa904Sopenharmony_ci      requested_fe_kind = corpus::CTF_ORIGIN;
1455e01aa904Sopenharmony_ci#endif
1456e01aa904Sopenharmony_ci    abigail::elf_based_reader_sptr reader =
1457e01aa904Sopenharmony_ci      create_best_elf_based_reader(elf2.path,
1458e01aa904Sopenharmony_ci				   di_dirs2,
1459e01aa904Sopenharmony_ci				   env, requested_fe_kind,
1460e01aa904Sopenharmony_ci				   opts.show_all_types);
1461e01aa904Sopenharmony_ci    ABG_ASSERT(reader);
1462e01aa904Sopenharmony_ci
1463e01aa904Sopenharmony_ci    reader->add_suppressions(priv_types_supprs2);
1464e01aa904Sopenharmony_ci    set_generic_options(*reader, opts);
1465e01aa904Sopenharmony_ci
1466e01aa904Sopenharmony_ci    corpus2 = reader->read_corpus(c2_status);
1467e01aa904Sopenharmony_ci
1468e01aa904Sopenharmony_ci    bool bail_out = false;
1469e01aa904Sopenharmony_ci    if (!(c2_status & abigail::fe_iface::STATUS_OK))
1470e01aa904Sopenharmony_ci      {
1471e01aa904Sopenharmony_ci	if (opts.verbose)
1472e01aa904Sopenharmony_ci	  emit_prefix("abipkgdiff", cerr)
1473e01aa904Sopenharmony_ci	    << "Could not find the read file '"
1474e01aa904Sopenharmony_ci	    << elf2.path
1475e01aa904Sopenharmony_ci	    << "' properly\n";
1476e01aa904Sopenharmony_ci
1477e01aa904Sopenharmony_ci	if (detailed_error_status)
1478e01aa904Sopenharmony_ci	  *detailed_error_status = c2_status;
1479e01aa904Sopenharmony_ci
1480e01aa904Sopenharmony_ci	bail_out = true;
1481e01aa904Sopenharmony_ci      }
1482e01aa904Sopenharmony_ci
1483e01aa904Sopenharmony_ci    if (opts.fail_if_no_debug_info)
1484e01aa904Sopenharmony_ci      {
1485e01aa904Sopenharmony_ci	bool debug_info_error = false;
1486e01aa904Sopenharmony_ci	if (c2_status & abigail::fe_iface::STATUS_DEBUG_INFO_NOT_FOUND)
1487e01aa904Sopenharmony_ci	  {
1488e01aa904Sopenharmony_ci	    if (opts.verbose)
1489e01aa904Sopenharmony_ci	      emit_prefix("abipkgdiff", cerr)
1490e01aa904Sopenharmony_ci		<< "while reading file" << elf2.path << "\n";
1491e01aa904Sopenharmony_ci
1492e01aa904Sopenharmony_ci	    emit_prefix("abipkgdiff", cerr) << "Could not find debug info file";
1493e01aa904Sopenharmony_ci	    if (di_dir2 && strcmp(di_dir2, ""))
1494e01aa904Sopenharmony_ci	      cerr << " under " << di_dir2 << "\n";
1495e01aa904Sopenharmony_ci	    else
1496e01aa904Sopenharmony_ci	      cerr << "\n";
1497e01aa904Sopenharmony_ci
1498e01aa904Sopenharmony_ci	    if (detailed_error_status)
1499e01aa904Sopenharmony_ci	      *detailed_error_status = c2_status;
1500e01aa904Sopenharmony_ci	    debug_info_error = true;
1501e01aa904Sopenharmony_ci	  }
1502e01aa904Sopenharmony_ci
1503e01aa904Sopenharmony_ci	if (c2_status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
1504e01aa904Sopenharmony_ci	  {
1505e01aa904Sopenharmony_ci	    if (opts.verbose)
1506e01aa904Sopenharmony_ci	      emit_prefix("abipkgdiff", cerr)
1507e01aa904Sopenharmony_ci		<< "while reading file" << elf2.path << "\n";
1508e01aa904Sopenharmony_ci
1509e01aa904Sopenharmony_ci	    emit_prefix("abipkgdiff", cerr)
1510e01aa904Sopenharmony_ci	      << "Could not find alternate debug info file";
1511e01aa904Sopenharmony_ci	    string alt_di_path;
1512e01aa904Sopenharmony_ci#ifdef WITH_CTF
1513e01aa904Sopenharmony_ci            if (opts.use_ctf)
1514e01aa904Sopenharmony_ci              ;
1515e01aa904Sopenharmony_ci            else
1516e01aa904Sopenharmony_ci#endif
1517e01aa904Sopenharmony_ci	      reader->refers_to_alt_debug_info(alt_di_path);
1518e01aa904Sopenharmony_ci	    if (!alt_di_path.empty())
1519e01aa904Sopenharmony_ci	      cerr << ": " << alt_di_path << "\n";
1520e01aa904Sopenharmony_ci	    else
1521e01aa904Sopenharmony_ci	      cerr << "\n";
1522e01aa904Sopenharmony_ci
1523e01aa904Sopenharmony_ci	    if (detailed_error_status)
1524e01aa904Sopenharmony_ci	      *detailed_error_status = c2_status;
1525e01aa904Sopenharmony_ci	    debug_info_error = true;
1526e01aa904Sopenharmony_ci	  }
1527e01aa904Sopenharmony_ci
1528e01aa904Sopenharmony_ci	if (debug_info_error)
1529e01aa904Sopenharmony_ci	  bail_out = true;
1530e01aa904Sopenharmony_ci      }
1531e01aa904Sopenharmony_ci
1532e01aa904Sopenharmony_ci    if (bail_out)
1533e01aa904Sopenharmony_ci      return abigail::tools_utils::ABIDIFF_ERROR;
1534e01aa904Sopenharmony_ci  }
1535e01aa904Sopenharmony_ci
1536e01aa904Sopenharmony_ci  if (opts.verbose)
1537e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
1538e01aa904Sopenharmony_ci      << " DONE reading file " << elf2.path << "\n";
1539e01aa904Sopenharmony_ci
1540e01aa904Sopenharmony_ci  if (opts.verbose)
1541e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
1542e01aa904Sopenharmony_ci      << "  Comparing the ABIs of: \n"
1543e01aa904Sopenharmony_ci      << "    " << elf1.path << "\n"
1544e01aa904Sopenharmony_ci      << "    " << elf2.path << "\n";
1545e01aa904Sopenharmony_ci
1546e01aa904Sopenharmony_ci  diff = compute_diff(corpus1, corpus2, ctxt);
1547e01aa904Sopenharmony_ci
1548e01aa904Sopenharmony_ci  if (opts.verbose)
1549e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
1550e01aa904Sopenharmony_ci      << "Comparing the ABIs of file "
1551e01aa904Sopenharmony_ci      << elf1.path
1552e01aa904Sopenharmony_ci      << " and "
1553e01aa904Sopenharmony_ci      << elf2.path
1554e01aa904Sopenharmony_ci      << " is DONE\n";
1555e01aa904Sopenharmony_ci
1556e01aa904Sopenharmony_ci  abidiff_status s = abigail::tools_utils::ABIDIFF_OK;
1557e01aa904Sopenharmony_ci  if (diff->has_net_changes())
1558e01aa904Sopenharmony_ci    s |= abigail::tools_utils::ABIDIFF_ABI_CHANGE;
1559e01aa904Sopenharmony_ci  if (diff->has_incompatible_changes())
1560e01aa904Sopenharmony_ci    s |= abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE;
1561e01aa904Sopenharmony_ci
1562e01aa904Sopenharmony_ci  return s;
1563e01aa904Sopenharmony_ci}
1564e01aa904Sopenharmony_ci
1565e01aa904Sopenharmony_ci/// Compare an ELF file to its ABIXML representation.
1566e01aa904Sopenharmony_ci///
1567e01aa904Sopenharmony_ci/// @param elf the ELF file to compare.
1568e01aa904Sopenharmony_ci///
1569e01aa904Sopenharmony_ci/// @param debug_dir the debug directory of the ELF file.
1570e01aa904Sopenharmony_ci///
1571e01aa904Sopenharmony_ci/// @param opts the options passed the user.
1572e01aa904Sopenharmony_ci///
1573e01aa904Sopenharmony_ci/// @param env the environment to use for the comparison.
1574e01aa904Sopenharmony_ci///
1575e01aa904Sopenharmony_ci/// @param diff the diff object resulting from the comparison of @p
1576e01aa904Sopenharmony_ci/// elf against its ABIXML representation.
1577e01aa904Sopenharmony_ci///
1578e01aa904Sopenharmony_ci/// @param ctxt the resulting diff context used for the comparison
1579e01aa904Sopenharmony_ci/// that yielded @p diff.
1580e01aa904Sopenharmony_ci///
1581e01aa904Sopenharmony_ci/// @param detailed_error_status the detailed error satus returned by
1582e01aa904Sopenharmony_ci/// this function.
1583e01aa904Sopenharmony_ci///
1584e01aa904Sopenharmony_ci/// @return the status of the self comparison.
1585e01aa904Sopenharmony_cistatic abidiff_status
1586e01aa904Sopenharmony_cicompare_to_self(const elf_file&		elf,
1587e01aa904Sopenharmony_ci		const string&			debug_dir,
1588e01aa904Sopenharmony_ci		const options&			opts,
1589e01aa904Sopenharmony_ci		abigail::ir::environment&	env,
1590e01aa904Sopenharmony_ci		corpus_diff_sptr&		diff,
1591e01aa904Sopenharmony_ci		diff_context_sptr&		ctxt,
1592e01aa904Sopenharmony_ci		abigail::fe_iface::status*	detailed_error_status = 0)
1593e01aa904Sopenharmony_ci{
1594e01aa904Sopenharmony_ci  char *di_dir = (char*) debug_dir.c_str();
1595e01aa904Sopenharmony_ci
1596e01aa904Sopenharmony_ci  vector<char**> di_dirs;
1597e01aa904Sopenharmony_ci  di_dirs.push_back(&di_dir);
1598e01aa904Sopenharmony_ci
1599e01aa904Sopenharmony_ci  abigail::fe_iface::status c_status = abigail::fe_iface::STATUS_OK;
1600e01aa904Sopenharmony_ci
1601e01aa904Sopenharmony_ci  if (opts.verbose)
1602e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
1603e01aa904Sopenharmony_ci      << "Comparing the ABI of file '"
1604e01aa904Sopenharmony_ci      << elf.path
1605e01aa904Sopenharmony_ci      << "' against itself ...\n";
1606e01aa904Sopenharmony_ci
1607e01aa904Sopenharmony_ci  if (opts.verbose)
1608e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
1609e01aa904Sopenharmony_ci      << "Reading file "
1610e01aa904Sopenharmony_ci      << elf.path
1611e01aa904Sopenharmony_ci      << " ...\n";
1612e01aa904Sopenharmony_ci
1613e01aa904Sopenharmony_ci  corpus_sptr corp;
1614e01aa904Sopenharmony_ci  abigail::elf_based_reader_sptr reader;
1615e01aa904Sopenharmony_ci  {
1616e01aa904Sopenharmony_ci    corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
1617e01aa904Sopenharmony_ci#ifdef WITH_CTF
1618e01aa904Sopenharmony_ci    if (opts.use_ctf)
1619e01aa904Sopenharmony_ci      requested_fe_kind = corpus::CTF_ORIGIN;
1620e01aa904Sopenharmony_ci#endif
1621e01aa904Sopenharmony_ci    abigail::elf_based_reader_sptr reader =
1622e01aa904Sopenharmony_ci      create_best_elf_based_reader(elf.path,
1623e01aa904Sopenharmony_ci				   di_dirs,
1624e01aa904Sopenharmony_ci				   env, requested_fe_kind,
1625e01aa904Sopenharmony_ci				   opts.show_all_types);
1626e01aa904Sopenharmony_ci    ABG_ASSERT(reader);
1627e01aa904Sopenharmony_ci
1628e01aa904Sopenharmony_ci    corp = reader->read_corpus(c_status);
1629e01aa904Sopenharmony_ci
1630e01aa904Sopenharmony_ci    if (!(c_status & abigail::fe_iface::STATUS_OK))
1631e01aa904Sopenharmony_ci      {
1632e01aa904Sopenharmony_ci	if (opts.verbose)
1633e01aa904Sopenharmony_ci	  emit_prefix("abipkgdiff", cerr)
1634e01aa904Sopenharmony_ci	    << "Could not read file '"
1635e01aa904Sopenharmony_ci	    << elf.path
1636e01aa904Sopenharmony_ci	    << "' propertly\n";
1637e01aa904Sopenharmony_ci
1638e01aa904Sopenharmony_ci	if (detailed_error_status)
1639e01aa904Sopenharmony_ci	  *detailed_error_status = c_status;
1640e01aa904Sopenharmony_ci
1641e01aa904Sopenharmony_ci	return abigail::tools_utils::ABIDIFF_ERROR;
1642e01aa904Sopenharmony_ci      }
1643e01aa904Sopenharmony_ci
1644e01aa904Sopenharmony_ci    if (opts.verbose)
1645e01aa904Sopenharmony_ci      emit_prefix("abipkgdiff", cerr)
1646e01aa904Sopenharmony_ci	<< "Read file '"
1647e01aa904Sopenharmony_ci	<< elf.path
1648e01aa904Sopenharmony_ci	<< "' OK\n";
1649e01aa904Sopenharmony_ci
1650e01aa904Sopenharmony_ci
1651e01aa904Sopenharmony_ci    ABG_ASSERT(corp);
1652e01aa904Sopenharmony_ci  }
1653e01aa904Sopenharmony_ci
1654e01aa904Sopenharmony_ci  corpus_sptr reread_corp;
1655e01aa904Sopenharmony_ci  string abi_file_path;
1656e01aa904Sopenharmony_ci  {
1657e01aa904Sopenharmony_ci    if (!opts.pkg1->create_abi_file_path(elf.path, abi_file_path))
1658e01aa904Sopenharmony_ci      {
1659e01aa904Sopenharmony_ci	if (opts.verbose)
1660e01aa904Sopenharmony_ci	  emit_prefix("abipkgdiff", cerr)
1661e01aa904Sopenharmony_ci	    << "Could not create the directory tree to store the abi for '"
1662e01aa904Sopenharmony_ci	    << elf.path
1663e01aa904Sopenharmony_ci	    << "'\n";
1664e01aa904Sopenharmony_ci
1665e01aa904Sopenharmony_ci	return abigail::tools_utils::ABIDIFF_ERROR;
1666e01aa904Sopenharmony_ci      }
1667e01aa904Sopenharmony_ci    ofstream of(abi_file_path.c_str(), std::ios_base::trunc);
1668e01aa904Sopenharmony_ci
1669e01aa904Sopenharmony_ci    {
1670e01aa904Sopenharmony_ci      const abigail::xml_writer::write_context_sptr c =
1671e01aa904Sopenharmony_ci	abigail::xml_writer::create_write_context(env, of);
1672e01aa904Sopenharmony_ci
1673e01aa904Sopenharmony_ci      if (opts.verbose)
1674e01aa904Sopenharmony_ci	emit_prefix("abipkgdiff", cerr)
1675e01aa904Sopenharmony_ci	  << "Writting ABIXML file '"
1676e01aa904Sopenharmony_ci	  << abi_file_path
1677e01aa904Sopenharmony_ci	  << "' ...\n";
1678e01aa904Sopenharmony_ci
1679e01aa904Sopenharmony_ci      if (!write_corpus(*c, corp, 0))
1680e01aa904Sopenharmony_ci	{
1681e01aa904Sopenharmony_ci	  if (opts.verbose)
1682e01aa904Sopenharmony_ci	    emit_prefix("abipkgdiff", cerr)
1683e01aa904Sopenharmony_ci	      << "Could not write the ABIXML file to '"
1684e01aa904Sopenharmony_ci	      << abi_file_path << "'\n";
1685e01aa904Sopenharmony_ci
1686e01aa904Sopenharmony_ci	  return abigail::tools_utils::ABIDIFF_ERROR;
1687e01aa904Sopenharmony_ci	}
1688e01aa904Sopenharmony_ci
1689e01aa904Sopenharmony_ci      of.flush();
1690e01aa904Sopenharmony_ci      of.close();
1691e01aa904Sopenharmony_ci
1692e01aa904Sopenharmony_ci      if (opts.verbose)
1693e01aa904Sopenharmony_ci	emit_prefix("abipkgdiff", cerr)
1694e01aa904Sopenharmony_ci	  << "Wrote ABIXML file '"
1695e01aa904Sopenharmony_ci	  << abi_file_path
1696e01aa904Sopenharmony_ci	  << "' OK\n";
1697e01aa904Sopenharmony_ci    }
1698e01aa904Sopenharmony_ci
1699e01aa904Sopenharmony_ci    {
1700e01aa904Sopenharmony_ci      abigail::fe_iface_sptr rdr = abixml::create_reader(abi_file_path, env);
1701e01aa904Sopenharmony_ci      if (!rdr)
1702e01aa904Sopenharmony_ci	{
1703e01aa904Sopenharmony_ci	  if (opts.verbose)
1704e01aa904Sopenharmony_ci	    emit_prefix("abipkgdiff", cerr)
1705e01aa904Sopenharmony_ci	      << "Could not create read context for ABIXML file '"
1706e01aa904Sopenharmony_ci	      << abi_file_path << "'\n";
1707e01aa904Sopenharmony_ci
1708e01aa904Sopenharmony_ci	  return abigail::tools_utils::ABIDIFF_ERROR;
1709e01aa904Sopenharmony_ci	}
1710e01aa904Sopenharmony_ci
1711e01aa904Sopenharmony_ci      if (opts.verbose)
1712e01aa904Sopenharmony_ci	emit_prefix("abipkgdiff", cerr)
1713e01aa904Sopenharmony_ci	  << "Reading ABIXML file '"
1714e01aa904Sopenharmony_ci	  << abi_file_path
1715e01aa904Sopenharmony_ci	  << "' ...\n";
1716e01aa904Sopenharmony_ci
1717e01aa904Sopenharmony_ci      abigail::fe_iface::status sts;
1718e01aa904Sopenharmony_ci      reread_corp = rdr->read_corpus(sts);
1719e01aa904Sopenharmony_ci      if (!reread_corp)
1720e01aa904Sopenharmony_ci	{
1721e01aa904Sopenharmony_ci	  if (opts.verbose)
1722e01aa904Sopenharmony_ci	    emit_prefix("abipkgdiff", cerr)
1723e01aa904Sopenharmony_ci	      << "Could not read temporary ABIXML file '"
1724e01aa904Sopenharmony_ci	      << abi_file_path << "'\n";
1725e01aa904Sopenharmony_ci
1726e01aa904Sopenharmony_ci	  return abigail::tools_utils::ABIDIFF_ERROR;
1727e01aa904Sopenharmony_ci	}
1728e01aa904Sopenharmony_ci
1729e01aa904Sopenharmony_ci      if (opts.verbose)
1730e01aa904Sopenharmony_ci	emit_prefix("abipkgdiff", cerr)
1731e01aa904Sopenharmony_ci	  << "Read file '"
1732e01aa904Sopenharmony_ci	  << abi_file_path
1733e01aa904Sopenharmony_ci	  << "' OK\n";
1734e01aa904Sopenharmony_ci    }
1735e01aa904Sopenharmony_ci  }
1736e01aa904Sopenharmony_ci
1737e01aa904Sopenharmony_ci  ctxt.reset(new diff_context);
1738e01aa904Sopenharmony_ci  set_diff_context_from_opts(ctxt, opts);
1739e01aa904Sopenharmony_ci
1740e01aa904Sopenharmony_ci  if (opts.verbose)
1741e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
1742e01aa904Sopenharmony_ci      << "Comparing the ABIs of: \n"
1743e01aa904Sopenharmony_ci      << "   '" << corp->get_path() << "' against \n"
1744e01aa904Sopenharmony_ci      << "   '" << abi_file_path << "'...\n";
1745e01aa904Sopenharmony_ci
1746e01aa904Sopenharmony_ci  diff = compute_diff(corp, reread_corp, ctxt);
1747e01aa904Sopenharmony_ci  if (opts.verbose)
1748e01aa904Sopenharmony_ci    emit_prefix("abipkgdfiff", cerr)
1749e01aa904Sopenharmony_ci      << "... Comparing the ABIs: DONE\n";
1750e01aa904Sopenharmony_ci
1751e01aa904Sopenharmony_ci  abidiff_status s = abigail::tools_utils::ABIDIFF_OK;
1752e01aa904Sopenharmony_ci  if (diff->has_changes())
1753e01aa904Sopenharmony_ci    s |= abigail::tools_utils::ABIDIFF_ABI_CHANGE;
1754e01aa904Sopenharmony_ci  if (diff->has_incompatible_changes())
1755e01aa904Sopenharmony_ci    s |= abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE;
1756e01aa904Sopenharmony_ci
1757e01aa904Sopenharmony_ci  if (opts.verbose)
1758e01aa904Sopenharmony_ci    emit_prefix("abipkgdfiff", cerr)
1759e01aa904Sopenharmony_ci      << "Comparison against self "
1760e01aa904Sopenharmony_ci      << (s == abigail::tools_utils::ABIDIFF_OK ? "SUCCEEDED" : "FAILED")
1761e01aa904Sopenharmony_ci      << '\n';
1762e01aa904Sopenharmony_ci
1763e01aa904Sopenharmony_ci  return s;
1764e01aa904Sopenharmony_ci}
1765e01aa904Sopenharmony_ci
1766e01aa904Sopenharmony_ci/// If devel packages were associated to the main package we are
1767e01aa904Sopenharmony_ci/// looking at, use the names of the header files (extracted from the
1768e01aa904Sopenharmony_ci/// package) to generate suppression specification to filter out types
1769e01aa904Sopenharmony_ci/// that are not defined in those header files.
1770e01aa904Sopenharmony_ci///
1771e01aa904Sopenharmony_ci/// Filtering out types not defined in publi headers amounts to filter
1772e01aa904Sopenharmony_ci/// out types that are deemed private to the package we are looking
1773e01aa904Sopenharmony_ci/// at.
1774e01aa904Sopenharmony_ci///
1775e01aa904Sopenharmony_ci/// If the function succeeds, it returns a non-empty vector of
1776e01aa904Sopenharmony_ci/// suppression specifications.
1777e01aa904Sopenharmony_ci///
1778e01aa904Sopenharmony_ci/// @param pkg the main package we are looking at.
1779e01aa904Sopenharmony_ci///
1780e01aa904Sopenharmony_ci/// @param opts the options of the current program.
1781e01aa904Sopenharmony_ci///
1782e01aa904Sopenharmony_ci/// @return a vector of suppression_sptr.  If no suppressions
1783e01aa904Sopenharmony_ci/// specification were constructed, the returned vector is empty.
1784e01aa904Sopenharmony_cistatic suppressions_type
1785e01aa904Sopenharmony_cicreate_private_types_suppressions(const package& pkg, const options &opts)
1786e01aa904Sopenharmony_ci{
1787e01aa904Sopenharmony_ci  suppressions_type supprs;
1788e01aa904Sopenharmony_ci
1789e01aa904Sopenharmony_ci  package_sptr devel_pkg = pkg.devel_package();
1790e01aa904Sopenharmony_ci  if (!devel_pkg
1791e01aa904Sopenharmony_ci      || !file_exists(devel_pkg->extracted_dir_path())
1792e01aa904Sopenharmony_ci      || !is_dir(devel_pkg->extracted_dir_path()))
1793e01aa904Sopenharmony_ci    return supprs;
1794e01aa904Sopenharmony_ci
1795e01aa904Sopenharmony_ci  string headers_path = devel_pkg->extracted_dir_path();
1796e01aa904Sopenharmony_ci  if (devel_pkg->type() == abigail::tools_utils::FILE_TYPE_RPM
1797e01aa904Sopenharmony_ci      ||devel_pkg->type() == abigail::tools_utils::FILE_TYPE_DEB)
1798e01aa904Sopenharmony_ci    // For RPM and DEB packages, header files are under the
1799e01aa904Sopenharmony_ci    // /usr/include sub-directories.
1800e01aa904Sopenharmony_ci    headers_path += "/usr/include";
1801e01aa904Sopenharmony_ci
1802e01aa904Sopenharmony_ci  if (!is_dir(headers_path))
1803e01aa904Sopenharmony_ci    return supprs;
1804e01aa904Sopenharmony_ci
1805e01aa904Sopenharmony_ci  suppression_sptr suppr =
1806e01aa904Sopenharmony_ci    gen_suppr_spec_from_headers(headers_path);
1807e01aa904Sopenharmony_ci
1808e01aa904Sopenharmony_ci  if (suppr)
1809e01aa904Sopenharmony_ci    {
1810e01aa904Sopenharmony_ci      if (opts.drop_private_types)
1811e01aa904Sopenharmony_ci	suppr->set_drops_artifact_from_ir(true);
1812e01aa904Sopenharmony_ci      supprs.push_back(suppr);
1813e01aa904Sopenharmony_ci    }
1814e01aa904Sopenharmony_ci
1815e01aa904Sopenharmony_ci  return supprs;
1816e01aa904Sopenharmony_ci}
1817e01aa904Sopenharmony_ci
1818e01aa904Sopenharmony_ci/// If the user wants to avoid comparing DSOs that are private to this
1819e01aa904Sopenharmony_ci/// package, then we build the set of public DSOs as advertised in the
1820e01aa904Sopenharmony_ci/// package's "provides" property.
1821e01aa904Sopenharmony_ci///
1822e01aa904Sopenharmony_ci/// Note that at the moment this function only works for RPMs.  It
1823e01aa904Sopenharmony_ci/// doesn't yet support other packaging formats.
1824e01aa904Sopenharmony_ci///
1825e01aa904Sopenharmony_ci/// @param pkg the package to consider.
1826e01aa904Sopenharmony_ci///
1827e01aa904Sopenharmony_ci/// @param opts the options of this program.
1828e01aa904Sopenharmony_ci///
1829e01aa904Sopenharmony_ci/// @return true iff the set of public DSOs was built.
1830e01aa904Sopenharmony_cistatic bool
1831e01aa904Sopenharmony_cimaybe_create_public_dso_sonames_set(package& pkg, const options &opts)
1832e01aa904Sopenharmony_ci{
1833e01aa904Sopenharmony_ci  if (opts.compare_private_dsos || !pkg.public_dso_sonames().empty())
1834e01aa904Sopenharmony_ci    return false;
1835e01aa904Sopenharmony_ci
1836e01aa904Sopenharmony_ci  if (pkg.type() == abigail::tools_utils::FILE_TYPE_RPM)
1837e01aa904Sopenharmony_ci    return get_dsos_provided_by_rpm(pkg.path(), pkg.public_dso_sonames());
1838e01aa904Sopenharmony_ci
1839e01aa904Sopenharmony_ci  // We don't support this yet for non-RPM packages.
1840e01aa904Sopenharmony_ci  return false;
1841e01aa904Sopenharmony_ci}
1842e01aa904Sopenharmony_ci
1843e01aa904Sopenharmony_ci/// Test if we should only compare the public DSOs of a given package.
1844e01aa904Sopenharmony_ci///
1845e01aa904Sopenharmony_ci/// @param pkg the package to consider.
1846e01aa904Sopenharmony_ci///
1847e01aa904Sopenharmony_ci/// @param opts the options of this program
1848e01aa904Sopenharmony_cistatic bool
1849e01aa904Sopenharmony_cimust_compare_public_dso_only(package& pkg, options& opts)
1850e01aa904Sopenharmony_ci{
1851e01aa904Sopenharmony_ci  if (pkg.type() == abigail::tools_utils::FILE_TYPE_RPM
1852e01aa904Sopenharmony_ci      && !opts.compare_private_dsos)
1853e01aa904Sopenharmony_ci    return true;
1854e01aa904Sopenharmony_ci
1855e01aa904Sopenharmony_ci  return false;
1856e01aa904Sopenharmony_ci}
1857e01aa904Sopenharmony_ci
1858e01aa904Sopenharmony_ci/// While walking a file directory, check if a directory entry is a
1859e01aa904Sopenharmony_ci/// kabi whitelist of a particular architecture.
1860e01aa904Sopenharmony_ci///
1861e01aa904Sopenharmony_ci/// If it is, then save its file path in a vector of whitelists.
1862e01aa904Sopenharmony_ci///
1863e01aa904Sopenharmony_ci/// @param entry the directory entry to consider.
1864e01aa904Sopenharmony_ci///
1865e01aa904Sopenharmony_ci/// @param arch the architecture to consider.
1866e01aa904Sopenharmony_ci///
1867e01aa904Sopenharmony_ci/// @param whitelists out parameter.  If @p entry is the whitelist we
1868e01aa904Sopenharmony_ci/// are looking for, add its path to this output parameter.
1869e01aa904Sopenharmony_cistatic void
1870e01aa904Sopenharmony_cimaybe_collect_kabi_whitelists(const FTSENT *entry,
1871e01aa904Sopenharmony_ci			      const string arch,
1872e01aa904Sopenharmony_ci			      vector<string> &whitelists)
1873e01aa904Sopenharmony_ci{
1874e01aa904Sopenharmony_ci  if (entry == NULL
1875e01aa904Sopenharmony_ci      || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
1876e01aa904Sopenharmony_ci      || entry->fts_info == FTS_ERR
1877e01aa904Sopenharmony_ci      || entry->fts_info == FTS_NS)
1878e01aa904Sopenharmony_ci    return;
1879e01aa904Sopenharmony_ci
1880e01aa904Sopenharmony_ci  string path = entry->fts_path;
1881e01aa904Sopenharmony_ci  maybe_get_symlink_target_file_path(path, path);
1882e01aa904Sopenharmony_ci
1883e01aa904Sopenharmony_ci  string kabi_whitelist_name = "kabi_whitelist_" + arch;
1884e01aa904Sopenharmony_ci
1885e01aa904Sopenharmony_ci  if (string_ends_with(path, kabi_whitelist_name))
1886e01aa904Sopenharmony_ci    whitelists.push_back(path);
1887e01aa904Sopenharmony_ci}
1888e01aa904Sopenharmony_ci
1889e01aa904Sopenharmony_ci/// Get the kabi whitelist for a particular architecture under a given
1890e01aa904Sopenharmony_ci/// directory.
1891e01aa904Sopenharmony_ci///
1892e01aa904Sopenharmony_ci/// @param dir the directory to look at.
1893e01aa904Sopenharmony_ci///
1894e01aa904Sopenharmony_ci/// @param arch the architecture to consider.
1895e01aa904Sopenharmony_ci///
1896e01aa904Sopenharmony_ci/// @param whitelist_paths the vector where to add the whitelists
1897e01aa904Sopenharmony_ci/// found.  Note that a whitelist is added to this parameter iff the
1898e01aa904Sopenharmony_ci/// function returns true.
1899e01aa904Sopenharmony_ci///
1900e01aa904Sopenharmony_ci/// @return true iff the function found a whitelist at least.
1901e01aa904Sopenharmony_cistatic bool
1902e01aa904Sopenharmony_ciget_kabi_whitelists_from_arch_under_dir(const string& dir,
1903e01aa904Sopenharmony_ci					const string& arch,
1904e01aa904Sopenharmony_ci					vector<string>& whitelist_paths)
1905e01aa904Sopenharmony_ci{
1906e01aa904Sopenharmony_ci bool is_ok = false;
1907e01aa904Sopenharmony_ci  char* paths[] = {const_cast<char*>(dir.c_str()), 0};
1908e01aa904Sopenharmony_ci
1909e01aa904Sopenharmony_ci  FTS *file_hierarchy = fts_open(paths, FTS_LOGICAL|FTS_NOCHDIR, NULL);
1910e01aa904Sopenharmony_ci  if (!file_hierarchy)
1911e01aa904Sopenharmony_ci    return is_ok;
1912e01aa904Sopenharmony_ci
1913e01aa904Sopenharmony_ci  FTSENT *entry;
1914e01aa904Sopenharmony_ci  while ((entry = fts_read(file_hierarchy)))
1915e01aa904Sopenharmony_ci    maybe_collect_kabi_whitelists(entry, arch, whitelist_paths);
1916e01aa904Sopenharmony_ci
1917e01aa904Sopenharmony_ci  fts_close(file_hierarchy);
1918e01aa904Sopenharmony_ci
1919e01aa904Sopenharmony_ci  return true;
1920e01aa904Sopenharmony_ci}
1921e01aa904Sopenharmony_ci
1922e01aa904Sopenharmony_ci/// Find a kabi whitelist in a linux kernel RPM package.
1923e01aa904Sopenharmony_ci///
1924e01aa904Sopenharmony_ci/// Note that the linux kernel RPM package must have been extracted
1925e01aa904Sopenharmony_ci/// somewhere already.
1926e01aa904Sopenharmony_ci///
1927e01aa904Sopenharmony_ci/// This function then looks for the whitelist under the /lib/modules
1928e01aa904Sopenharmony_ci/// directory inside the extracted content of the package.  If it
1929e01aa904Sopenharmony_ci/// finds it and saves its file path in the
1930e01aa904Sopenharmony_ci/// options::kabi_whitelist_paths data member.
1931e01aa904Sopenharmony_ci///
1932e01aa904Sopenharmony_ci/// @param pkg the linux kernel package to consider.
1933e01aa904Sopenharmony_ci///
1934e01aa904Sopenharmony_ci/// @param opts the options the program was invoked with.
1935e01aa904Sopenharmony_cistatic bool
1936e01aa904Sopenharmony_cimaybe_handle_kabi_whitelist_pkg(const package& pkg, options &opts)
1937e01aa904Sopenharmony_ci{
1938e01aa904Sopenharmony_ci  if (opts.kabi_whitelist_packages.empty()
1939e01aa904Sopenharmony_ci      || !opts.kabi_whitelist_paths.empty()
1940e01aa904Sopenharmony_ci      || !pkg.kabi_whitelist_package())
1941e01aa904Sopenharmony_ci    return false;
1942e01aa904Sopenharmony_ci
1943e01aa904Sopenharmony_ci  if (pkg.type() != abigail::tools_utils::FILE_TYPE_RPM)
1944e01aa904Sopenharmony_ci    return false;
1945e01aa904Sopenharmony_ci
1946e01aa904Sopenharmony_ci  string pkg_name = pkg.base_name();
1947e01aa904Sopenharmony_ci  bool is_linux_kernel_package = file_is_kernel_package(pkg_name, pkg.type());
1948e01aa904Sopenharmony_ci
1949e01aa904Sopenharmony_ci  if (!is_linux_kernel_package)
1950e01aa904Sopenharmony_ci    return false;
1951e01aa904Sopenharmony_ci
1952e01aa904Sopenharmony_ci  package_sptr kabi_wl_pkg = pkg.kabi_whitelist_package();
1953e01aa904Sopenharmony_ci  assert(kabi_wl_pkg);
1954e01aa904Sopenharmony_ci
1955e01aa904Sopenharmony_ci  if (!file_exists(kabi_wl_pkg->extracted_dir_path())
1956e01aa904Sopenharmony_ci      || !is_dir(kabi_wl_pkg->extracted_dir_path()))
1957e01aa904Sopenharmony_ci    return false;
1958e01aa904Sopenharmony_ci
1959e01aa904Sopenharmony_ci  string rpm_arch;
1960e01aa904Sopenharmony_ci  if (!get_rpm_arch(pkg_name, rpm_arch))
1961e01aa904Sopenharmony_ci    return false;
1962e01aa904Sopenharmony_ci
1963e01aa904Sopenharmony_ci  string kabi_wl_path = kabi_wl_pkg->extracted_dir_path();
1964e01aa904Sopenharmony_ci  kabi_wl_path += "/lib/modules";
1965e01aa904Sopenharmony_ci  vector<string> whitelist_paths;
1966e01aa904Sopenharmony_ci
1967e01aa904Sopenharmony_ci  get_kabi_whitelists_from_arch_under_dir(kabi_wl_path, rpm_arch,
1968e01aa904Sopenharmony_ci					  whitelist_paths);
1969e01aa904Sopenharmony_ci
1970e01aa904Sopenharmony_ci  if (!whitelist_paths.empty())
1971e01aa904Sopenharmony_ci    {
1972e01aa904Sopenharmony_ci      std::sort(whitelist_paths.begin(), whitelist_paths.end());
1973e01aa904Sopenharmony_ci      opts.kabi_whitelist_paths.push_back(whitelist_paths.back());
1974e01aa904Sopenharmony_ci    }
1975e01aa904Sopenharmony_ci
1976e01aa904Sopenharmony_ci  return true;
1977e01aa904Sopenharmony_ci}
1978e01aa904Sopenharmony_ci
1979e01aa904Sopenharmony_ci/// The task that performs the extraction of the content of several
1980e01aa904Sopenharmony_ci/// packages into a temporary directory.
1981e01aa904Sopenharmony_ci///
1982e01aa904Sopenharmony_ci/// If this task has several packages to extract, then it extracts
1983e01aa904Sopenharmony_ci/// them in sequence.
1984e01aa904Sopenharmony_ci///
1985e01aa904Sopenharmony_ci/// Note that several instances of tasks can perform their jobs (i.e
1986e01aa904Sopenharmony_ci/// extract packages in sequence) in parallel.
1987e01aa904Sopenharmony_ciclass pkg_extraction_task : public task
1988e01aa904Sopenharmony_ci{
1989e01aa904Sopenharmony_ci  pkg_extraction_task();
1990e01aa904Sopenharmony_ci
1991e01aa904Sopenharmony_cipublic:
1992e01aa904Sopenharmony_ci  vector<package_sptr> pkgs;
1993e01aa904Sopenharmony_ci  const options &opts;
1994e01aa904Sopenharmony_ci  bool is_ok;
1995e01aa904Sopenharmony_ci
1996e01aa904Sopenharmony_ci  pkg_extraction_task(const package_sptr &p, const options &o)
1997e01aa904Sopenharmony_ci    : opts(o), is_ok(true)
1998e01aa904Sopenharmony_ci  {pkgs.push_back(p);}
1999e01aa904Sopenharmony_ci
2000e01aa904Sopenharmony_ci  pkg_extraction_task(const vector<package_sptr> &packages, const options &o)
2001e01aa904Sopenharmony_ci    : pkgs(packages), opts(o), is_ok(true)
2002e01aa904Sopenharmony_ci  {}
2003e01aa904Sopenharmony_ci
2004e01aa904Sopenharmony_ci  /// The job performed by the current task, which is to extract its
2005e01aa904Sopenharmony_ci  /// packages in sequence.  This job is to be performed in parallel
2006e01aa904Sopenharmony_ci  /// with other jobs of other tasks.
2007e01aa904Sopenharmony_ci  virtual void
2008e01aa904Sopenharmony_ci  perform()
2009e01aa904Sopenharmony_ci  {
2010e01aa904Sopenharmony_ci    for (vector<package_sptr>::const_iterator p = pkgs.begin();
2011e01aa904Sopenharmony_ci	 p != pkgs.end();
2012e01aa904Sopenharmony_ci	 ++p)
2013e01aa904Sopenharmony_ci      is_ok &= extract_package(**p, opts);
2014e01aa904Sopenharmony_ci  }
2015e01aa904Sopenharmony_ci}; //end class pkg_extraction_task
2016e01aa904Sopenharmony_ci
2017e01aa904Sopenharmony_ci/// A convenience typedef for a shared pointer to @f pkg_extraction_task.
2018e01aa904Sopenharmony_citypedef shared_ptr<pkg_extraction_task> pkg_extraction_task_sptr;
2019e01aa904Sopenharmony_ci
2020e01aa904Sopenharmony_ci/// The worker task which job is to prepares a package.
2021e01aa904Sopenharmony_ci///
2022e01aa904Sopenharmony_ci/// Preparing a package means:
2023e01aa904Sopenharmony_ci///
2024e01aa904Sopenharmony_ci/// 	1/ Extract the package and its ancillary packages.
2025e01aa904Sopenharmony_ci///
2026e01aa904Sopenharmony_ci/// 	2/ Analyze the extracted content, map that content so that we
2027e01aa904Sopenharmony_ci/// 	determine what the ELF files to be analyze are.
2028e01aa904Sopenharmony_ciclass pkg_prepare_task : public abigail::workers::task
2029e01aa904Sopenharmony_ci{
2030e01aa904Sopenharmony_ci  pkg_prepare_task();
2031e01aa904Sopenharmony_ci
2032e01aa904Sopenharmony_cipublic:
2033e01aa904Sopenharmony_ci  package_sptr pkg;
2034e01aa904Sopenharmony_ci  options &opts;
2035e01aa904Sopenharmony_ci  bool is_ok;
2036e01aa904Sopenharmony_ci
2037e01aa904Sopenharmony_ci  pkg_prepare_task(package_sptr &p, options &o)
2038e01aa904Sopenharmony_ci    : pkg(p), opts(o), is_ok(false)
2039e01aa904Sopenharmony_ci  {}
2040e01aa904Sopenharmony_ci
2041e01aa904Sopenharmony_ci  /// The job performed by this task.
2042e01aa904Sopenharmony_ci  virtual void
2043e01aa904Sopenharmony_ci  perform()
2044e01aa904Sopenharmony_ci  {
2045e01aa904Sopenharmony_ci    is_ok = pkg && extract_package_and_map_its_content(pkg, opts);
2046e01aa904Sopenharmony_ci  }
2047e01aa904Sopenharmony_ci}; //end class pkg_prepare_task
2048e01aa904Sopenharmony_ci
2049e01aa904Sopenharmony_ci/// A convenience typedef for a shared_ptr to @ref pkg_prepare_task
2050e01aa904Sopenharmony_citypedef shared_ptr<pkg_prepare_task> pkg_prepare_task_sptr;
2051e01aa904Sopenharmony_ci
2052e01aa904Sopenharmony_ci/// The worker task which job is to compare two ELF binaries
2053e01aa904Sopenharmony_ciclass compare_task : public abigail::workers::task
2054e01aa904Sopenharmony_ci{
2055e01aa904Sopenharmony_cipublic:
2056e01aa904Sopenharmony_ci
2057e01aa904Sopenharmony_ci  compare_args_sptr args;
2058e01aa904Sopenharmony_ci  abidiff_status status;
2059e01aa904Sopenharmony_ci  ostringstream out;
2060e01aa904Sopenharmony_ci  string pretty_output;
2061e01aa904Sopenharmony_ci
2062e01aa904Sopenharmony_ci  compare_task()
2063e01aa904Sopenharmony_ci    : status(abigail::tools_utils::ABIDIFF_OK)
2064e01aa904Sopenharmony_ci  {}
2065e01aa904Sopenharmony_ci
2066e01aa904Sopenharmony_ci  compare_task(const compare_args_sptr& a)
2067e01aa904Sopenharmony_ci    : args(a),
2068e01aa904Sopenharmony_ci      status(abigail::tools_utils::ABIDIFF_OK)
2069e01aa904Sopenharmony_ci  {}
2070e01aa904Sopenharmony_ci
2071e01aa904Sopenharmony_ci  /// The job performed by the task.
2072e01aa904Sopenharmony_ci  ///
2073e01aa904Sopenharmony_ci  /// This compares two ELF files, gets the resulting test report and
2074e01aa904Sopenharmony_ci  /// stores it in an output stream.
2075e01aa904Sopenharmony_ci  virtual void
2076e01aa904Sopenharmony_ci  perform()
2077e01aa904Sopenharmony_ci  {
2078e01aa904Sopenharmony_ci    abigail::ir::environment env;
2079e01aa904Sopenharmony_ci    diff_context_sptr ctxt;
2080e01aa904Sopenharmony_ci    corpus_diff_sptr diff;
2081e01aa904Sopenharmony_ci
2082e01aa904Sopenharmony_ci    abigail::fe_iface::status detailed_status =
2083e01aa904Sopenharmony_ci      abigail::fe_iface::STATUS_UNKNOWN;
2084e01aa904Sopenharmony_ci
2085e01aa904Sopenharmony_ci    if (args->opts.exported_interfaces_only.has_value())
2086e01aa904Sopenharmony_ci      env.analyze_exported_interfaces_only
2087e01aa904Sopenharmony_ci	(*args->opts.exported_interfaces_only);
2088e01aa904Sopenharmony_ci
2089e01aa904Sopenharmony_ci    status |= compare(args->elf1, args->debug_dir1, args->private_types_suppr1,
2090e01aa904Sopenharmony_ci		      args->elf2, args->debug_dir2, args->private_types_suppr2,
2091e01aa904Sopenharmony_ci		      args->opts, env, diff, ctxt, &detailed_status);
2092e01aa904Sopenharmony_ci
2093e01aa904Sopenharmony_ci    // If there is an ABI change, tell the user about it.
2094e01aa904Sopenharmony_ci    if ((status & abigail::tools_utils::ABIDIFF_ABI_CHANGE)
2095e01aa904Sopenharmony_ci	||( diff && diff->has_net_changes()))
2096e01aa904Sopenharmony_ci      {
2097e01aa904Sopenharmony_ci	diff->report(out, /*prefix=*/"  ");
2098e01aa904Sopenharmony_ci	string name = args->elf1.name;
2099e01aa904Sopenharmony_ci
2100e01aa904Sopenharmony_ci	pretty_output +=
2101e01aa904Sopenharmony_ci	  string("================ changes of '") + name + "'===============\n"
2102e01aa904Sopenharmony_ci	  + out.str()
2103e01aa904Sopenharmony_ci	  + "================ end of changes of '"
2104e01aa904Sopenharmony_ci	  + name + "'===============\n\n";
2105e01aa904Sopenharmony_ci      }
2106e01aa904Sopenharmony_ci    else
2107e01aa904Sopenharmony_ci      {
2108e01aa904Sopenharmony_ci	if (args->opts.show_identical_binaries)
2109e01aa904Sopenharmony_ci	  out << "No ABI change detected\n";
2110e01aa904Sopenharmony_ci      }
2111e01aa904Sopenharmony_ci
2112e01aa904Sopenharmony_ci    // If an error happened while comparing the two binaries, tell the
2113e01aa904Sopenharmony_ci    // user about it.
2114e01aa904Sopenharmony_ci    if (status & abigail::tools_utils::ABIDIFF_ERROR)
2115e01aa904Sopenharmony_ci      {
2116e01aa904Sopenharmony_ci	string diagnostic =
2117e01aa904Sopenharmony_ci	  abigail::status_to_diagnostic_string(detailed_status);
2118e01aa904Sopenharmony_ci	if (diagnostic.empty())
2119e01aa904Sopenharmony_ci	  diagnostic =
2120e01aa904Sopenharmony_ci	    "Unknown error.  Please run the tool again with --verbose\n";
2121e01aa904Sopenharmony_ci
2122e01aa904Sopenharmony_ci	string name = args->elf1.name;
2123e01aa904Sopenharmony_ci	pretty_output +=
2124e01aa904Sopenharmony_ci	  "==== Error happened during processing of '" + name + "' ====\n";
2125e01aa904Sopenharmony_ci	pretty_output += diagnostic;
2126e01aa904Sopenharmony_ci	pretty_output +=
2127e01aa904Sopenharmony_ci	  "==== End of error for '" + name + "' ====\n";
2128e01aa904Sopenharmony_ci      }
2129e01aa904Sopenharmony_ci  }
2130e01aa904Sopenharmony_ci}; // end class compare_task
2131e01aa904Sopenharmony_ci
2132e01aa904Sopenharmony_ci/// Convenience typedef for a shared_ptr of @ref compare_task.
2133e01aa904Sopenharmony_citypedef shared_ptr<compare_task> compare_task_sptr;
2134e01aa904Sopenharmony_ci
2135e01aa904Sopenharmony_ci/// The worker task which job is to compare an ELF binary to its ABI
2136e01aa904Sopenharmony_ci/// representation.
2137e01aa904Sopenharmony_ciclass self_compare_task : public compare_task
2138e01aa904Sopenharmony_ci{
2139e01aa904Sopenharmony_cipublic:
2140e01aa904Sopenharmony_ci  self_compare_task(const compare_args_sptr& a)
2141e01aa904Sopenharmony_ci    : compare_task(a)
2142e01aa904Sopenharmony_ci  {}
2143e01aa904Sopenharmony_ci
2144e01aa904Sopenharmony_ci  /// The job performed by the task.
2145e01aa904Sopenharmony_ci  ///
2146e01aa904Sopenharmony_ci  /// This compares an ELF file to its ABIXML representation and
2147e01aa904Sopenharmony_ci  /// expects the result to be the empty set.
2148e01aa904Sopenharmony_ci  virtual void
2149e01aa904Sopenharmony_ci  perform()
2150e01aa904Sopenharmony_ci  {
2151e01aa904Sopenharmony_ci    abigail::ir::environment env;
2152e01aa904Sopenharmony_ci    diff_context_sptr ctxt;
2153e01aa904Sopenharmony_ci    corpus_diff_sptr diff;
2154e01aa904Sopenharmony_ci
2155e01aa904Sopenharmony_ci    if (args->opts.exported_interfaces_only.has_value())
2156e01aa904Sopenharmony_ci      env.analyze_exported_interfaces_only
2157e01aa904Sopenharmony_ci	(*args->opts.exported_interfaces_only);
2158e01aa904Sopenharmony_ci
2159e01aa904Sopenharmony_ci    abigail::fe_iface::status detailed_status =
2160e01aa904Sopenharmony_ci      abigail::fe_iface::STATUS_UNKNOWN;
2161e01aa904Sopenharmony_ci
2162e01aa904Sopenharmony_ci    status |= compare_to_self(args->elf1, args->debug_dir1,
2163e01aa904Sopenharmony_ci			      args->opts, env, diff, ctxt,
2164e01aa904Sopenharmony_ci			      &detailed_status);
2165e01aa904Sopenharmony_ci
2166e01aa904Sopenharmony_ci    string name = args->elf1.name;
2167e01aa904Sopenharmony_ci    if (status == abigail::tools_utils::ABIDIFF_OK)
2168e01aa904Sopenharmony_ci      pretty_output += "==== SELF CHECK SUCCEEDED for '"+ name + "' ====\n";
2169e01aa904Sopenharmony_ci    else if ((status & abigail::tools_utils::ABIDIFF_ABI_CHANGE)
2170e01aa904Sopenharmony_ci	     ||( diff && diff->has_net_changes()))
2171e01aa904Sopenharmony_ci      {
2172e01aa904Sopenharmony_ci	// There is an ABI change, tell the user about it.
2173e01aa904Sopenharmony_ci	diff->report(out, /*indent=*/"  ");
2174e01aa904Sopenharmony_ci
2175e01aa904Sopenharmony_ci	pretty_output +=
2176e01aa904Sopenharmony_ci	  string("======== comparing'") + name +
2177e01aa904Sopenharmony_ci	  "' to itself wrongly yielded result: ===========\n"
2178e01aa904Sopenharmony_ci	  + out.str()
2179e01aa904Sopenharmony_ci	  + "===SELF CHECK FAILED for '"+ name + "'\n";
2180e01aa904Sopenharmony_ci      }
2181e01aa904Sopenharmony_ci
2182e01aa904Sopenharmony_ci    // If an error happened while comparing the two binaries, tell the
2183e01aa904Sopenharmony_ci    // user about it.
2184e01aa904Sopenharmony_ci    if (status & abigail::tools_utils::ABIDIFF_ERROR)
2185e01aa904Sopenharmony_ci      {
2186e01aa904Sopenharmony_ci	string diagnostic =
2187e01aa904Sopenharmony_ci	  abigail::status_to_diagnostic_string(detailed_status);
2188e01aa904Sopenharmony_ci
2189e01aa904Sopenharmony_ci	if (diagnostic.empty())
2190e01aa904Sopenharmony_ci	  diagnostic =
2191e01aa904Sopenharmony_ci	    "Unknown error.  Please run the tool again with --verbose\n";
2192e01aa904Sopenharmony_ci
2193e01aa904Sopenharmony_ci	string name = args->elf1.name;
2194e01aa904Sopenharmony_ci	pretty_output +=
2195e01aa904Sopenharmony_ci	  "==== Error happened during self check of '" + name + "' ====\n";
2196e01aa904Sopenharmony_ci	pretty_output += diagnostic;
2197e01aa904Sopenharmony_ci	pretty_output +=
2198e01aa904Sopenharmony_ci	  "==== SELF CHECK FAILED for '" + name + "' ====\n";
2199e01aa904Sopenharmony_ci
2200e01aa904Sopenharmony_ci      }
2201e01aa904Sopenharmony_ci  }
2202e01aa904Sopenharmony_ci}; // end class self_compare
2203e01aa904Sopenharmony_ci
2204e01aa904Sopenharmony_ci/// Convenience typedef for a shared_ptr of @ref compare_task.
2205e01aa904Sopenharmony_citypedef shared_ptr<self_compare_task> self_compare_task_sptr;
2206e01aa904Sopenharmony_ci
2207e01aa904Sopenharmony_ci/// This function is a sub-routine of create_maps_of_package_content.
2208e01aa904Sopenharmony_ci///
2209e01aa904Sopenharmony_ci/// It's called during the walking of the directory tree containing
2210e01aa904Sopenharmony_ci/// the extracted content of package.  It's called with an entry of
2211e01aa904Sopenharmony_ci/// that directory tree.
2212e01aa904Sopenharmony_ci///
2213e01aa904Sopenharmony_ci/// Depending on the kind of file this function is called on, it
2214e01aa904Sopenharmony_ci/// updates the vector of paths of the directory and the set of
2215e01aa904Sopenharmony_ci/// suppression paths found.
2216e01aa904Sopenharmony_ci///
2217e01aa904Sopenharmony_ci/// @param entry the directory entry to analyze.
2218e01aa904Sopenharmony_ci///
2219e01aa904Sopenharmony_ci/// @param opts the options of the current program.
2220e01aa904Sopenharmony_ci///
2221e01aa904Sopenharmony_ci/// @param file_name_to_look_for if this parameter is set, the
2222e01aa904Sopenharmony_ci/// function only looks for a file name which name is the same as the
2223e01aa904Sopenharmony_ci/// value of this parameter.
2224e01aa904Sopenharmony_ci///
2225e01aa904Sopenharmony_ci/// @param paths out parameter.  This is the set of meaningful paths
2226e01aa904Sopenharmony_ci/// of the current directory tree being analyzed.  These paths are
2227e01aa904Sopenharmony_ci/// those that are going to be involved in ABI comparison.
2228e01aa904Sopenharmony_cistatic void
2229e01aa904Sopenharmony_cimaybe_update_package_content(const FTSENT *entry,
2230e01aa904Sopenharmony_ci			     options &opts,
2231e01aa904Sopenharmony_ci			     const string& file_name_to_look_for,
2232e01aa904Sopenharmony_ci			     unordered_set<string>& paths)
2233e01aa904Sopenharmony_ci{
2234e01aa904Sopenharmony_ci  if (entry == NULL
2235e01aa904Sopenharmony_ci      || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
2236e01aa904Sopenharmony_ci      || entry->fts_info == FTS_ERR
2237e01aa904Sopenharmony_ci      || entry->fts_info == FTS_NS)
2238e01aa904Sopenharmony_ci    return;
2239e01aa904Sopenharmony_ci
2240e01aa904Sopenharmony_ci  string path = entry->fts_path;
2241e01aa904Sopenharmony_ci  maybe_get_symlink_target_file_path(path, path);
2242e01aa904Sopenharmony_ci
2243e01aa904Sopenharmony_ci  if (!file_name_to_look_for.empty())
2244e01aa904Sopenharmony_ci    {
2245e01aa904Sopenharmony_ci      string name;
2246e01aa904Sopenharmony_ci      abigail::tools_utils::base_name(path, name);
2247e01aa904Sopenharmony_ci      if (name == file_name_to_look_for)
2248e01aa904Sopenharmony_ci	paths.insert(path);
2249e01aa904Sopenharmony_ci      return;
2250e01aa904Sopenharmony_ci    }
2251e01aa904Sopenharmony_ci
2252e01aa904Sopenharmony_ci  if (guess_file_type(path) == abigail::tools_utils::FILE_TYPE_ELF)
2253e01aa904Sopenharmony_ci    paths.insert(path);
2254e01aa904Sopenharmony_ci  else if (opts.abignore && string_ends_with(path, ".abignore"))
2255e01aa904Sopenharmony_ci    opts.suppression_paths.push_back(path);
2256e01aa904Sopenharmony_ci}
2257e01aa904Sopenharmony_ci
2258e01aa904Sopenharmony_ci/// Walk a given directory to collect files that are "interesting" to
2259e01aa904Sopenharmony_ci/// analyze.  By default, "interesting" means interesting from either
2260e01aa904Sopenharmony_ci/// a kernel package or a userspace binary analysis point of view.
2261e01aa904Sopenharmony_ci///
2262e01aa904Sopenharmony_ci/// @param dir the directory to walk.
2263e01aa904Sopenharmony_ci///
2264e01aa904Sopenharmony_ci/// @param file_name_to_look_for if this parameter is set, only a file
2265e01aa904Sopenharmony_ci/// with this name is going to be collected.
2266e01aa904Sopenharmony_ci///
2267e01aa904Sopenharmony_ci/// @param interesting_files out parameter.  This parameter is
2268e01aa904Sopenharmony_ci/// populated with the interesting files found by the function iff the
2269e01aa904Sopenharmony_ci/// function returns true.
2270e01aa904Sopenharmony_ci///
2271e01aa904Sopenharmony_ci/// @return true iff the function completed successfully.
2272e01aa904Sopenharmony_cistatic bool
2273e01aa904Sopenharmony_ciget_interesting_files_under_dir(const string dir,
2274e01aa904Sopenharmony_ci				const string& file_name_to_look_for,
2275e01aa904Sopenharmony_ci				options& opts,
2276e01aa904Sopenharmony_ci				vector<string>& interesting_files)
2277e01aa904Sopenharmony_ci{
2278e01aa904Sopenharmony_ci  bool is_ok = false;
2279e01aa904Sopenharmony_ci  string root;
2280e01aa904Sopenharmony_ci  real_path(dir, root);
2281e01aa904Sopenharmony_ci  if (root.empty())
2282e01aa904Sopenharmony_ci    root = dir;
2283e01aa904Sopenharmony_ci
2284e01aa904Sopenharmony_ci  char* paths[] = {const_cast<char*>(root.c_str()), 0};
2285e01aa904Sopenharmony_ci
2286e01aa904Sopenharmony_ci  FTS *file_hierarchy = fts_open(paths, FTS_LOGICAL|FTS_NOCHDIR, NULL);
2287e01aa904Sopenharmony_ci  if (!file_hierarchy)
2288e01aa904Sopenharmony_ci    return is_ok;
2289e01aa904Sopenharmony_ci
2290e01aa904Sopenharmony_ci  FTSENT *entry;
2291e01aa904Sopenharmony_ci  unordered_set<string> files;
2292e01aa904Sopenharmony_ci  while ((entry = fts_read(file_hierarchy)))
2293e01aa904Sopenharmony_ci    maybe_update_package_content(entry, opts, file_name_to_look_for, files);
2294e01aa904Sopenharmony_ci
2295e01aa904Sopenharmony_ci  for (unordered_set<string>::const_iterator i = files.begin();
2296e01aa904Sopenharmony_ci       i != files.end();
2297e01aa904Sopenharmony_ci       ++i)
2298e01aa904Sopenharmony_ci    interesting_files.push_back(*i);
2299e01aa904Sopenharmony_ci
2300e01aa904Sopenharmony_ci  fts_close(file_hierarchy);
2301e01aa904Sopenharmony_ci
2302e01aa904Sopenharmony_ci  is_ok = true;
2303e01aa904Sopenharmony_ci
2304e01aa904Sopenharmony_ci  return is_ok;
2305e01aa904Sopenharmony_ci}
2306e01aa904Sopenharmony_ci
2307e01aa904Sopenharmony_ci/// Create maps of the content of a given package.
2308e01aa904Sopenharmony_ci///
2309e01aa904Sopenharmony_ci/// The maps contain relevant metadata about the content of the
2310e01aa904Sopenharmony_ci/// files.  These maps are used afterwards during the comparison of
2311e01aa904Sopenharmony_ci/// the content of the package.  Note that the maps are stored in the
2312e01aa904Sopenharmony_ci/// object that represents that package.
2313e01aa904Sopenharmony_ci///
2314e01aa904Sopenharmony_ci/// @param package the package to consider.
2315e01aa904Sopenharmony_ci///
2316e01aa904Sopenharmony_ci/// @param opts the options the current program has been called with.
2317e01aa904Sopenharmony_ci///
2318e01aa904Sopenharmony_ci/// @param true upon successful completion, false otherwise.
2319e01aa904Sopenharmony_cistatic bool
2320e01aa904Sopenharmony_cicreate_maps_of_package_content(package& package, options& opts)
2321e01aa904Sopenharmony_ci{
2322e01aa904Sopenharmony_ci  if (opts.verbose)
2323e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
2324e01aa904Sopenharmony_ci      << "Analyzing the content of package "
2325e01aa904Sopenharmony_ci      << package.path()
2326e01aa904Sopenharmony_ci      << " extracted to "
2327e01aa904Sopenharmony_ci      << package.extracted_dir_path()
2328e01aa904Sopenharmony_ci      << " ...\n";
2329e01aa904Sopenharmony_ci
2330e01aa904Sopenharmony_ci  bool is_ok = true;
2331e01aa904Sopenharmony_ci  vector<string> elf_file_paths;
2332e01aa904Sopenharmony_ci
2333e01aa904Sopenharmony_ci  // if package is linux kernel package and its associated debug
2334e01aa904Sopenharmony_ci  // info package looks like a kernel debuginfo package, then try to
2335e01aa904Sopenharmony_ci  // go find the vmlinux file in that debug info file.
2336e01aa904Sopenharmony_ci  string pkg_name = package.base_name();
2337e01aa904Sopenharmony_ci  bool is_linux_kernel_package = file_is_kernel_package(pkg_name,
2338e01aa904Sopenharmony_ci							package.type());
2339e01aa904Sopenharmony_ci  if (is_linux_kernel_package)
2340e01aa904Sopenharmony_ci    {
2341e01aa904Sopenharmony_ci      // For a linux kernel package, no analysis is done.  It'll be
2342e01aa904Sopenharmony_ci      // done later at comparison time by
2343e01aa904Sopenharmony_ci      // compare_prepared_linux_kernel_packages
2344e01aa904Sopenharmony_ci      is_ok = true;
2345e01aa904Sopenharmony_ci      if (opts.verbose)
2346e01aa904Sopenharmony_ci	emit_prefix("abipkgdiff", cerr)
2347e01aa904Sopenharmony_ci	  << " Analysis of " << package.path() << " DONE\n";
2348e01aa904Sopenharmony_ci      return is_ok;
2349e01aa904Sopenharmony_ci    }
2350e01aa904Sopenharmony_ci
2351e01aa904Sopenharmony_ci  is_ok &= get_interesting_files_under_dir(package.extracted_dir_path(),
2352e01aa904Sopenharmony_ci					   /*file_name_to_look_for=*/"",
2353e01aa904Sopenharmony_ci					   opts, elf_file_paths);
2354e01aa904Sopenharmony_ci
2355e01aa904Sopenharmony_ci  if (opts.verbose)
2356e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
2357e01aa904Sopenharmony_ci      << "Found " << elf_file_paths.size() << " files in "
2358e01aa904Sopenharmony_ci      << package.extracted_dir_path() << "\n";
2359e01aa904Sopenharmony_ci
2360e01aa904Sopenharmony_ci  // determine if all files have the same prefix.  Compute that prefix
2361e01aa904Sopenharmony_ci  // and stick it into the package!  That prefix is going to be used
2362e01aa904Sopenharmony_ci  // later by the package::convert_path_to_unique_suffix method.
2363e01aa904Sopenharmony_ci  package.load_elf_file_paths(opts);
2364e01aa904Sopenharmony_ci
2365e01aa904Sopenharmony_ci  maybe_create_public_dso_sonames_set(package, opts);
2366e01aa904Sopenharmony_ci
2367e01aa904Sopenharmony_ci  for (vector<string>::const_iterator file = elf_file_paths.begin();
2368e01aa904Sopenharmony_ci       file != elf_file_paths.end();
2369e01aa904Sopenharmony_ci       ++file)
2370e01aa904Sopenharmony_ci    {
2371e01aa904Sopenharmony_ci      elf_file_sptr e (new elf_file(*file));
2372e01aa904Sopenharmony_ci      if (opts.compare_dso_only)
2373e01aa904Sopenharmony_ci	{
2374e01aa904Sopenharmony_ci	  if (e->type != abigail::elf::ELF_TYPE_DSO)
2375e01aa904Sopenharmony_ci	    {
2376e01aa904Sopenharmony_ci	      if (opts.verbose)
2377e01aa904Sopenharmony_ci		emit_prefix("abipkgdiff", cerr)
2378e01aa904Sopenharmony_ci		  << "skipping non-DSO file " << e->path << "\n";
2379e01aa904Sopenharmony_ci	      continue;
2380e01aa904Sopenharmony_ci	    }
2381e01aa904Sopenharmony_ci	}
2382e01aa904Sopenharmony_ci      else
2383e01aa904Sopenharmony_ci	{
2384e01aa904Sopenharmony_ci	  if (e->type != abigail::elf::ELF_TYPE_DSO
2385e01aa904Sopenharmony_ci	      && e->type != abigail::elf::ELF_TYPE_EXEC
2386e01aa904Sopenharmony_ci              && e->type != abigail::elf::ELF_TYPE_PI_EXEC)
2387e01aa904Sopenharmony_ci	    {
2388e01aa904Sopenharmony_ci	      if (is_linux_kernel_package)
2389e01aa904Sopenharmony_ci		{
2390e01aa904Sopenharmony_ci		  if (e->type == abigail::elf::ELF_TYPE_RELOCATABLE)
2391e01aa904Sopenharmony_ci		    {
2392e01aa904Sopenharmony_ci		      // This is a Linux Kernel module.
2393e01aa904Sopenharmony_ci		      ;
2394e01aa904Sopenharmony_ci		    }
2395e01aa904Sopenharmony_ci		}
2396e01aa904Sopenharmony_ci	      else if (opts.verbose)
2397e01aa904Sopenharmony_ci		{
2398e01aa904Sopenharmony_ci		  emit_prefix("abipkgdiff", cerr)
2399e01aa904Sopenharmony_ci		    << "skipping non-DSO non-executable file "
2400e01aa904Sopenharmony_ci		    << e->path
2401e01aa904Sopenharmony_ci		    << "\n";
2402e01aa904Sopenharmony_ci		  continue;
2403e01aa904Sopenharmony_ci		}
2404e01aa904Sopenharmony_ci	    }
2405e01aa904Sopenharmony_ci	}
2406e01aa904Sopenharmony_ci
2407e01aa904Sopenharmony_ci      if (e->soname.empty())
2408e01aa904Sopenharmony_ci	{
2409e01aa904Sopenharmony_ci	  if (e->type == abigail::elf::ELF_TYPE_DSO
2410e01aa904Sopenharmony_ci	      && must_compare_public_dso_only(package, opts))
2411e01aa904Sopenharmony_ci	    {
2412e01aa904Sopenharmony_ci	      // We are instructed to compare public DSOs only.  Yet
2413e01aa904Sopenharmony_ci	      // this DSO does not have a soname.  so it can not be a
2414e01aa904Sopenharmony_ci	      // public DSO.  Let's skip it.
2415e01aa904Sopenharmony_ci	      if (opts.verbose)
2416e01aa904Sopenharmony_ci		emit_prefix("abipkgdiff", cerr)
2417e01aa904Sopenharmony_ci		  << "DSO " << e->path
2418e01aa904Sopenharmony_ci		  << " does not have a soname so it's private.  Skipping it\n";
2419e01aa904Sopenharmony_ci	      continue;
2420e01aa904Sopenharmony_ci	    }
2421e01aa904Sopenharmony_ci
2422e01aa904Sopenharmony_ci	  // Several binaries at different paths can have the same
2423e01aa904Sopenharmony_ci	  // base name.  So let's consider the full path of the binary
2424e01aa904Sopenharmony_ci	  // inside the extracted directory.
2425e01aa904Sopenharmony_ci	  string key = e->name;
2426e01aa904Sopenharmony_ci	  package.convert_path_to_unique_suffix(e->path, key);
2427e01aa904Sopenharmony_ci	  package.path_elf_file_sptr_map()[key] = e;
2428e01aa904Sopenharmony_ci	  if (opts.verbose)
2429e01aa904Sopenharmony_ci	    emit_prefix("abipkgdiff", cerr)
2430e01aa904Sopenharmony_ci	      << "mapped binary with key '" << key << "'"
2431e01aa904Sopenharmony_ci	      << "\n";
2432e01aa904Sopenharmony_ci	}
2433e01aa904Sopenharmony_ci      else
2434e01aa904Sopenharmony_ci	{
2435e01aa904Sopenharmony_ci	  // Several binaries at different paths can have the same
2436e01aa904Sopenharmony_ci	  // soname.  So let's *also* consider the full path of the
2437e01aa904Sopenharmony_ci	  // binary inside the extracted directory, not just the
2438e01aa904Sopenharmony_ci	  // soname.
2439e01aa904Sopenharmony_ci	  string key = e->soname;
2440e01aa904Sopenharmony_ci
2441e01aa904Sopenharmony_ci	  if (must_compare_public_dso_only(package, opts))
2442e01aa904Sopenharmony_ci	    {
2443e01aa904Sopenharmony_ci	      if (package.public_dso_sonames().find(key)
2444e01aa904Sopenharmony_ci		  == package.public_dso_sonames().end())
2445e01aa904Sopenharmony_ci		{
2446e01aa904Sopenharmony_ci		  // We are instructed to compare public DSOs only and
2447e01aa904Sopenharmony_ci		  // this one seems to be private.  So skip it.
2448e01aa904Sopenharmony_ci		  if (opts.verbose)
2449e01aa904Sopenharmony_ci		    emit_prefix("abipkgdiff", cerr)
2450e01aa904Sopenharmony_ci		      << "DSO " << e->path << " of soname " << key
2451e01aa904Sopenharmony_ci		      << " seems to be private.  Skipping it\n";
2452e01aa904Sopenharmony_ci		  continue;
2453e01aa904Sopenharmony_ci		}
2454e01aa904Sopenharmony_ci	    }
2455e01aa904Sopenharmony_ci
2456e01aa904Sopenharmony_ci	  if (package.convert_path_to_unique_suffix(e->path, key))
2457e01aa904Sopenharmony_ci	    {
2458e01aa904Sopenharmony_ci	      dir_name(key, key);
2459e01aa904Sopenharmony_ci	      key += string("/@soname:") + e->soname;
2460e01aa904Sopenharmony_ci	    }
2461e01aa904Sopenharmony_ci	  package.path_elf_file_sptr_map()[key] = e;
2462e01aa904Sopenharmony_ci	  if (opts.verbose)
2463e01aa904Sopenharmony_ci	    emit_prefix("abipkgdiff", cerr)
2464e01aa904Sopenharmony_ci	      << "mapped binary with key '" << key << "'"
2465e01aa904Sopenharmony_ci	      << "\n";
2466e01aa904Sopenharmony_ci	}
2467e01aa904Sopenharmony_ci    }
2468e01aa904Sopenharmony_ci
2469e01aa904Sopenharmony_ci  if (opts.verbose)
2470e01aa904Sopenharmony_ci    emit_prefix("abipkgdiff", cerr)
2471e01aa904Sopenharmony_ci      << " Analysis of " << package.path() << " DONE\n";
2472e01aa904Sopenharmony_ci
2473e01aa904Sopenharmony_ci  is_ok = true;
2474e01aa904Sopenharmony_ci
2475e01aa904Sopenharmony_ci  return is_ok;
2476e01aa904Sopenharmony_ci}
2477e01aa904Sopenharmony_ci
2478e01aa904Sopenharmony_ci/// Extract the content of a package (and its ancillary packages) and
2479e01aa904Sopenharmony_ci/// map its content.
2480e01aa904Sopenharmony_ci///
2481e01aa904Sopenharmony_ci/// First, the content of the package and its ancillary packages are
2482e01aa904Sopenharmony_ci/// extracted, in parallel.
2483e01aa904Sopenharmony_ci///
2484e01aa904Sopenharmony_ci/// Then, after that extraction is done, the content of the package if
2485e01aa904Sopenharmony_ci/// walked and analyzed.
2486e01aa904Sopenharmony_ci///
2487e01aa904Sopenharmony_ci/// @param pkg the package to extract and to analyze.
2488e01aa904Sopenharmony_ci///
2489e01aa904Sopenharmony_ci/// @param opts the options of the current program.
2490e01aa904Sopenharmony_ci///
2491e01aa904Sopenharmony_ci/// @return true iff the extraction and analyzing went well.
2492e01aa904Sopenharmony_cistatic bool
2493e01aa904Sopenharmony_ciextract_package_and_map_its_content(const package_sptr &pkg, options &opts)
2494e01aa904Sopenharmony_ci{
2495e01aa904Sopenharmony_ci  assert(pkg);
2496e01aa904Sopenharmony_ci
2497e01aa904Sopenharmony_ci  pkg_extraction_task_sptr main_pkg_extraction;
2498e01aa904Sopenharmony_ci  pkg_extraction_task_sptr dbg_extraction;
2499e01aa904Sopenharmony_ci  pkg_extraction_task_sptr devel_extraction;
2500e01aa904Sopenharmony_ci  pkg_extraction_task_sptr kabi_whitelist_extraction;
2501e01aa904Sopenharmony_ci
2502e01aa904Sopenharmony_ci  size_t NUM_EXTRACTIONS = 1;
2503e01aa904Sopenharmony_ci
2504e01aa904Sopenharmony_ci  main_pkg_extraction.reset(new pkg_extraction_task(pkg, opts));
2505e01aa904Sopenharmony_ci
2506e01aa904Sopenharmony_ci  if (!pkg->debug_info_packages().empty())
2507e01aa904Sopenharmony_ci    {
2508e01aa904Sopenharmony_ci      dbg_extraction.reset(new pkg_extraction_task(pkg->debug_info_packages(),
2509e01aa904Sopenharmony_ci						   opts));
2510e01aa904Sopenharmony_ci      ++NUM_EXTRACTIONS;
2511e01aa904Sopenharmony_ci    }
2512e01aa904Sopenharmony_ci
2513e01aa904Sopenharmony_ci  if (package_sptr devel_pkg = pkg->devel_package())
2514e01aa904Sopenharmony_ci    {
2515e01aa904Sopenharmony_ci      devel_extraction.reset(new pkg_extraction_task(devel_pkg, opts));
2516e01aa904Sopenharmony_ci      ++NUM_EXTRACTIONS;
2517e01aa904Sopenharmony_ci    }
2518e01aa904Sopenharmony_ci
2519e01aa904Sopenharmony_ci  if (package_sptr kabi_wl_pkg = pkg->kabi_whitelist_package())
2520e01aa904Sopenharmony_ci    {
2521e01aa904Sopenharmony_ci      kabi_whitelist_extraction.reset(new pkg_extraction_task(kabi_wl_pkg,
2522e01aa904Sopenharmony_ci							      opts));
2523e01aa904Sopenharmony_ci      ++NUM_EXTRACTIONS;
2524e01aa904Sopenharmony_ci    }
2525e01aa904Sopenharmony_ci
2526e01aa904Sopenharmony_ci  size_t num_workers = (opts.parallel
2527e01aa904Sopenharmony_ci			? std::min(opts.num_workers, NUM_EXTRACTIONS)
2528e01aa904Sopenharmony_ci			: 1);
2529e01aa904Sopenharmony_ci  abigail::workers::queue extraction_queue(num_workers);
2530e01aa904Sopenharmony_ci
2531e01aa904Sopenharmony_ci  // Perform the extraction of the NUM_WORKERS packages in parallel.
2532e01aa904Sopenharmony_ci  extraction_queue.schedule_task(dbg_extraction);
2533e01aa904Sopenharmony_ci  extraction_queue.schedule_task(main_pkg_extraction);
2534e01aa904Sopenharmony_ci  extraction_queue.schedule_task(devel_extraction);
2535e01aa904Sopenharmony_ci  extraction_queue.schedule_task(kabi_whitelist_extraction);
2536e01aa904Sopenharmony_ci
2537e01aa904Sopenharmony_ci  // Wait for the extraction to be done.
2538e01aa904Sopenharmony_ci  extraction_queue.wait_for_workers_to_complete();
2539e01aa904Sopenharmony_ci
2540e01aa904Sopenharmony_ci  // Analyze and map the content of the extracted package.
2541e01aa904Sopenharmony_ci  bool is_ok = false;
2542e01aa904Sopenharmony_ci  if (main_pkg_extraction->is_ok)
2543e01aa904Sopenharmony_ci    is_ok = create_maps_of_package_content(*pkg, opts);
2544e01aa904Sopenharmony_ci
2545e01aa904Sopenharmony_ci  if (is_ok)
2546e01aa904Sopenharmony_ci    maybe_handle_kabi_whitelist_pkg(*pkg, opts);
2547e01aa904Sopenharmony_ci
2548e01aa904Sopenharmony_ci  return is_ok;
2549e01aa904Sopenharmony_ci}
2550e01aa904Sopenharmony_ci
2551e01aa904Sopenharmony_ci/// Extract the two packages (and their ancillary packages) and
2552e01aa904Sopenharmony_ci/// analyze their content, so that we later know what files from the
2553e01aa904Sopenharmony_ci/// first package to compare against what files from the second
2554e01aa904Sopenharmony_ci/// package.
2555e01aa904Sopenharmony_ci///
2556e01aa904Sopenharmony_ci/// Note that preparing the first package and its ancillary packages
2557e01aa904Sopenharmony_ci/// happens in parallel with preparing the second package and its
2558e01aa904Sopenharmony_ci/// ancillary packages.  The function then waits for the two
2559e01aa904Sopenharmony_ci/// preparations to complete before returning.
2560e01aa904Sopenharmony_ci///
2561e01aa904Sopenharmony_ci/// @param first_package the first package to consider.
2562e01aa904Sopenharmony_ci///
2563e01aa904Sopenharmony_ci/// @param second_package the second package to consider.
2564e01aa904Sopenharmony_ci///
2565e01aa904Sopenharmony_ci/// @param opts the options of the current program.
2566e01aa904Sopenharmony_ci///
2567e01aa904Sopenharmony_ci/// @return true iff the preparation went well.
2568e01aa904Sopenharmony_cistatic bool
2569e01aa904Sopenharmony_ciprepare_packages(package_sptr &first_package,
2570e01aa904Sopenharmony_ci		 package_sptr &second_package,
2571e01aa904Sopenharmony_ci		 options &opts)
2572e01aa904Sopenharmony_ci{
2573e01aa904Sopenharmony_ci  pkg_prepare_task_sptr first_pkg_prepare;
2574e01aa904Sopenharmony_ci  pkg_prepare_task_sptr second_pkg_prepare;
2575e01aa904Sopenharmony_ci  size_t NUM_PREPARATIONS = 2;
2576e01aa904Sopenharmony_ci
2577e01aa904Sopenharmony_ci  first_pkg_prepare.reset(new pkg_prepare_task(first_package, opts));
2578e01aa904Sopenharmony_ci  second_pkg_prepare.reset(new pkg_prepare_task(second_package, opts));
2579e01aa904Sopenharmony_ci
2580e01aa904Sopenharmony_ci  size_t num_workers = (opts.parallel
2581e01aa904Sopenharmony_ci			? std::min(opts.num_workers, NUM_PREPARATIONS)
2582e01aa904Sopenharmony_ci			: 1);
2583e01aa904Sopenharmony_ci  abigail::workers::queue preparation_queue(num_workers);
2584e01aa904Sopenharmony_ci
2585e01aa904Sopenharmony_ci  preparation_queue.schedule_task(first_pkg_prepare);
2586e01aa904Sopenharmony_ci  preparation_queue.schedule_task(second_pkg_prepare);
2587e01aa904Sopenharmony_ci
2588e01aa904Sopenharmony_ci  preparation_queue.wait_for_workers_to_complete();
2589e01aa904Sopenharmony_ci
2590e01aa904Sopenharmony_ci  return first_pkg_prepare->is_ok && second_pkg_prepare->is_ok;
2591e01aa904Sopenharmony_ci}
2592e01aa904Sopenharmony_ci
2593e01aa904Sopenharmony_ci/// Prepare one package for the sake of comparing it to its ABIXML
2594e01aa904Sopenharmony_ci/// representation.
2595e01aa904Sopenharmony_ci///
2596e01aa904Sopenharmony_ci/// The preparation entails unpacking the content of the package into
2597e01aa904Sopenharmony_ci/// a temporary directory and mapping its content.
2598e01aa904Sopenharmony_ci///
2599e01aa904Sopenharmony_ci/// @param pkg the package to prepare.
2600e01aa904Sopenharmony_ci///
2601e01aa904Sopenharmony_ci/// @param opts the options provided by the user.
2602e01aa904Sopenharmony_ci///
2603e01aa904Sopenharmony_ci/// @return true iff the preparation succeeded.
2604e01aa904Sopenharmony_cistatic bool
2605e01aa904Sopenharmony_ciprepare_package(package_sptr& pkg, options &opts)
2606e01aa904Sopenharmony_ci{return extract_package_and_map_its_content(pkg, opts);}
2607e01aa904Sopenharmony_ci
2608e01aa904Sopenharmony_ci/// Compare the added sizes of an ELF pair (specified by a comparison
2609e01aa904Sopenharmony_ci/// task that compares two ELF files) against the added sizes of a
2610e01aa904Sopenharmony_ci/// second ELF pair.
2611e01aa904Sopenharmony_ci///
2612e01aa904Sopenharmony_ci/// Larger filesize strongly raises the possibility of larger debug-info,
2613e01aa904Sopenharmony_ci/// hence longer diff time. For a package containing several relatively
2614e01aa904Sopenharmony_ci/// large and small ELFs, it is often more efficient to start working on
2615e01aa904Sopenharmony_ci/// the larger ones first. This function is used to order the pairs by
2616e01aa904Sopenharmony_ci/// size, starting from the largest.
2617e01aa904Sopenharmony_ci///
2618e01aa904Sopenharmony_ci/// @param t1 the first comparison task that compares a pair of ELF
2619e01aa904Sopenharmony_ci/// files.
2620e01aa904Sopenharmony_ci///
2621e01aa904Sopenharmony_ci/// @param t2 the second comparison task that compares a pair of ELF
2622e01aa904Sopenharmony_ci/// files.
2623e01aa904Sopenharmony_ci///
2624e01aa904Sopenharmony_ci/// @return true if @p task1 is greater than @p task2.
2625e01aa904Sopenharmony_cibool
2626e01aa904Sopenharmony_cielf_size_is_greater(const task_sptr &task1,
2627e01aa904Sopenharmony_ci		    const task_sptr &task2)
2628e01aa904Sopenharmony_ci{
2629e01aa904Sopenharmony_ci  compare_task_sptr t1 = dynamic_pointer_cast<compare_task>(task1);
2630e01aa904Sopenharmony_ci  compare_task_sptr t2 = dynamic_pointer_cast<compare_task>(task2);
2631e01aa904Sopenharmony_ci
2632e01aa904Sopenharmony_ci  ABG_ASSERT(t1->args && t2->args);
2633e01aa904Sopenharmony_ci  off_t s1 = t1->args->elf1.size + t1->args->elf2.size;
2634e01aa904Sopenharmony_ci  off_t s2 = t2->args->elf1.size + t2->args->elf2.size;
2635e01aa904Sopenharmony_ci
2636e01aa904Sopenharmony_ci  if (s1 != s2)
2637e01aa904Sopenharmony_ci    return s1 > s2;
2638e01aa904Sopenharmony_ci
2639e01aa904Sopenharmony_ci  // The sizes of the compared binaries are the same.  So sort them
2640e01aa904Sopenharmony_ci  // lexicographically.
2641e01aa904Sopenharmony_ci  return t1->args->elf1.name < t2->args->elf1.name;
2642e01aa904Sopenharmony_ci
2643e01aa904Sopenharmony_ci}
2644e01aa904Sopenharmony_ci
2645e01aa904Sopenharmony_ci/// This type is used to notify the calling thread that the comparison
2646e01aa904Sopenharmony_ci/// of two ELF files is done.
2647e01aa904Sopenharmony_ciclass comparison_done_notify : public abigail::workers::queue::task_done_notify
2648e01aa904Sopenharmony_ci{
2649e01aa904Sopenharmony_ci  comparison_done_notify();
2650e01aa904Sopenharmony_ci
2651e01aa904Sopenharmony_cipublic:
2652e01aa904Sopenharmony_ci  abi_diff& diff;
2653e01aa904Sopenharmony_ci  abidiff_status status;
2654e01aa904Sopenharmony_ci
2655e01aa904Sopenharmony_ci  comparison_done_notify(abi_diff &d)
2656e01aa904Sopenharmony_ci    : diff(d),
2657e01aa904Sopenharmony_ci      status(abigail::tools_utils::ABIDIFF_OK)
2658e01aa904Sopenharmony_ci  {}
2659e01aa904Sopenharmony_ci
2660e01aa904Sopenharmony_ci  /// This operator is invoked by the worker queue whenever a
2661e01aa904Sopenharmony_ci  /// comparison task is done.
2662e01aa904Sopenharmony_ci  ///
2663e01aa904Sopenharmony_ci  /// The operator collects the status of the job of the task and also
2664e01aa904Sopenharmony_ci  /// updates the the count of binaries that have ABI changes.
2665e01aa904Sopenharmony_ci  ///
2666e01aa904Sopenharmony_ci  /// @param task_done the task that is done.
2667e01aa904Sopenharmony_ci  virtual void
2668e01aa904Sopenharmony_ci  operator()(const task_sptr& task_done)
2669e01aa904Sopenharmony_ci  {
2670e01aa904Sopenharmony_ci    compare_task_sptr comp_task = dynamic_pointer_cast<compare_task>(task_done);
2671e01aa904Sopenharmony_ci    assert(comp_task);
2672e01aa904Sopenharmony_ci
2673e01aa904Sopenharmony_ci    status |= comp_task->status;
2674e01aa904Sopenharmony_ci
2675e01aa904Sopenharmony_ci    if (status != abigail::tools_utils::ABIDIFF_OK)
2676e01aa904Sopenharmony_ci      {
2677e01aa904Sopenharmony_ci	string name = comp_task->args->elf1.name;
2678e01aa904Sopenharmony_ci
2679e01aa904Sopenharmony_ci	if (status & abigail::tools_utils::ABIDIFF_ABI_CHANGE)
2680e01aa904Sopenharmony_ci	  diff.changed_binaries.push_back(name);
2681e01aa904Sopenharmony_ci      }
2682e01aa904Sopenharmony_ci  }
2683e01aa904Sopenharmony_ci}; // end struct comparison_done_notify
2684e01aa904Sopenharmony_ci
2685e01aa904Sopenharmony_ci/// Erase the temporary directories that might have been created while
2686e01aa904Sopenharmony_ci/// handling two packages, unless the user asked to keep the temporary
2687e01aa904Sopenharmony_ci/// directories around.
2688e01aa904Sopenharmony_ci///
2689e01aa904Sopenharmony_ci/// @param first_package the first package to consider.
2690e01aa904Sopenharmony_ci///
2691e01aa904Sopenharmony_ci/// @param second_package the second package to consider.
2692e01aa904Sopenharmony_ci///
2693e01aa904Sopenharmony_ci/// @param opts the options passed to the program.
2694e01aa904Sopenharmony_cistatic void
2695e01aa904Sopenharmony_cimaybe_erase_temp_dirs(package& first_package, package& second_package,
2696e01aa904Sopenharmony_ci		      options& opts)
2697e01aa904Sopenharmony_ci{
2698e01aa904Sopenharmony_ci  if (opts.keep_tmp_files)
2699e01aa904Sopenharmony_ci    return;
2700e01aa904Sopenharmony_ci
2701e01aa904Sopenharmony_ci  erase_created_temporary_directories(first_package, second_package, opts);
2702e01aa904Sopenharmony_ci  erase_created_temporary_directories_parent(opts);
2703e01aa904Sopenharmony_ci}
2704e01aa904Sopenharmony_ci
2705e01aa904Sopenharmony_ci/// Compare the ABI of two prepared packages that contain userspace
2706e01aa904Sopenharmony_ci/// binaries.
2707e01aa904Sopenharmony_ci///
2708e01aa904Sopenharmony_ci/// A prepared package is a package which content has been extracted
2709e01aa904Sopenharmony_ci/// and mapped.
2710e01aa904Sopenharmony_ci///
2711e01aa904Sopenharmony_ci/// @param first_package the first package to consider.
2712e01aa904Sopenharmony_ci///
2713e01aa904Sopenharmony_ci/// @param second_package the second package to consider.
2714e01aa904Sopenharmony_ci///
2715e01aa904Sopenharmony_ci/// @param options the options the current program has been called
2716e01aa904Sopenharmony_ci/// with.
2717e01aa904Sopenharmony_ci///
2718e01aa904Sopenharmony_ci/// @param diff out parameter.  If this function returns true, then
2719e01aa904Sopenharmony_ci/// this parameter is set to the result of the comparison.
2720e01aa904Sopenharmony_ci///
2721e01aa904Sopenharmony_ci/// @param opts the options of the current program.
2722e01aa904Sopenharmony_ci///
2723e01aa904Sopenharmony_ci/// @return the status of the comparison.
2724e01aa904Sopenharmony_cistatic abidiff_status
2725e01aa904Sopenharmony_cicompare_prepared_userspace_packages(package& first_package,
2726e01aa904Sopenharmony_ci				    package& second_package,
2727e01aa904Sopenharmony_ci				    abi_diff& diff, options& opts)
2728e01aa904Sopenharmony_ci{
2729e01aa904Sopenharmony_ci  abidiff_status status = abigail::tools_utils::ABIDIFF_OK;
2730e01aa904Sopenharmony_ci  abigail::workers::queue::tasks_type compare_tasks;
2731e01aa904Sopenharmony_ci  string pkg_name = first_package.base_name();
2732e01aa904Sopenharmony_ci
2733e01aa904Sopenharmony_ci  // Setting debug-info path of libraries
2734e01aa904Sopenharmony_ci  string debug_dir1, debug_dir2, relative_debug_path = "/usr/lib/debug/";
2735e01aa904Sopenharmony_ci  if (!first_package.debug_info_packages().empty()
2736e01aa904Sopenharmony_ci      && !second_package.debug_info_packages().empty())
2737e01aa904Sopenharmony_ci    {
2738e01aa904Sopenharmony_ci      debug_dir1 =
2739e01aa904Sopenharmony_ci	first_package.debug_info_packages().front()->extracted_dir_path() +
2740e01aa904Sopenharmony_ci	relative_debug_path;
2741e01aa904Sopenharmony_ci      debug_dir2 =
2742e01aa904Sopenharmony_ci	second_package.debug_info_packages().front()->extracted_dir_path() +
2743e01aa904Sopenharmony_ci	relative_debug_path;
2744e01aa904Sopenharmony_ci    }
2745e01aa904Sopenharmony_ci
2746e01aa904Sopenharmony_ci  for (map<string, elf_file_sptr>::iterator it =
2747e01aa904Sopenharmony_ci	 first_package.path_elf_file_sptr_map().begin();
2748e01aa904Sopenharmony_ci       it != first_package.path_elf_file_sptr_map().end();
2749e01aa904Sopenharmony_ci       ++it)
2750e01aa904Sopenharmony_ci    {
2751e01aa904Sopenharmony_ci      map<string, elf_file_sptr>::iterator iter =
2752e01aa904Sopenharmony_ci	second_package.path_elf_file_sptr_map().find(it->first);
2753e01aa904Sopenharmony_ci
2754e01aa904Sopenharmony_ci      if (iter != second_package.path_elf_file_sptr_map().end()
2755e01aa904Sopenharmony_ci	  && (iter->second->type == abigail::elf::ELF_TYPE_DSO
2756e01aa904Sopenharmony_ci	      || iter->second->type == abigail::elf::ELF_TYPE_EXEC
2757e01aa904Sopenharmony_ci              || iter->second->type == abigail::elf::ELF_TYPE_PI_EXEC
2758e01aa904Sopenharmony_ci	      || iter->second->type == abigail::elf::ELF_TYPE_RELOCATABLE))
2759e01aa904Sopenharmony_ci	{
2760e01aa904Sopenharmony_ci	  if (iter->second->type != abigail::elf::ELF_TYPE_RELOCATABLE)
2761e01aa904Sopenharmony_ci	    {
2762e01aa904Sopenharmony_ci	      if (opts.verbose)
2763e01aa904Sopenharmony_ci		emit_prefix("abipkgdiff", cerr)
2764e01aa904Sopenharmony_ci		  << "Going to compare files '"
2765e01aa904Sopenharmony_ci		  << it->first << "' and '" << iter->first << "'\n";
2766e01aa904Sopenharmony_ci	      compare_args_sptr args
2767e01aa904Sopenharmony_ci		(new compare_args(*it->second,
2768e01aa904Sopenharmony_ci				  debug_dir1,
2769e01aa904Sopenharmony_ci				  create_private_types_suppressions
2770e01aa904Sopenharmony_ci				  (first_package, opts),
2771e01aa904Sopenharmony_ci				  *iter->second,
2772e01aa904Sopenharmony_ci				  debug_dir2,
2773e01aa904Sopenharmony_ci				  create_private_types_suppressions
2774e01aa904Sopenharmony_ci				  (second_package, opts), opts));
2775e01aa904Sopenharmony_ci	      compare_task_sptr t(new compare_task(args));
2776e01aa904Sopenharmony_ci	      compare_tasks.push_back(t);
2777e01aa904Sopenharmony_ci	    }
2778e01aa904Sopenharmony_ci	  second_package.path_elf_file_sptr_map().erase(iter);
2779e01aa904Sopenharmony_ci	}
2780e01aa904Sopenharmony_ci      else if (iter == second_package.path_elf_file_sptr_map().end())
2781e01aa904Sopenharmony_ci	{
2782e01aa904Sopenharmony_ci	  if (opts.verbose)
2783e01aa904Sopenharmony_ci	    emit_prefix("abipkgdiff", cerr)
2784e01aa904Sopenharmony_ci	      << "Detected removed file:  '"
2785e01aa904Sopenharmony_ci	      << it->first << "'\n";
2786e01aa904Sopenharmony_ci	  diff.removed_binaries.push_back(it->second);
2787e01aa904Sopenharmony_ci	  status |= abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE;
2788e01aa904Sopenharmony_ci	  status |= abigail::tools_utils::ABIDIFF_ABI_CHANGE;
2789e01aa904Sopenharmony_ci	}
2790e01aa904Sopenharmony_ci    }
2791e01aa904Sopenharmony_ci
2792e01aa904Sopenharmony_ci  comparison_done_notify notifier(diff);
2793e01aa904Sopenharmony_ci  if (!compare_tasks.empty())
2794e01aa904Sopenharmony_ci    {
2795e01aa904Sopenharmony_ci      // Larger elfs are processed first, since it's usually safe to assume
2796e01aa904Sopenharmony_ci      // their debug-info is larger as well, but the results are still
2797e01aa904Sopenharmony_ci      // in a map ordered by looked up in elf.name order.
2798e01aa904Sopenharmony_ci      std::sort(compare_tasks.begin(), compare_tasks.end(), elf_size_is_greater);
2799e01aa904Sopenharmony_ci
2800e01aa904Sopenharmony_ci      // There's no reason to spawn more workers than there are ELF pairs
2801e01aa904Sopenharmony_ci      // to be compared.
2802e01aa904Sopenharmony_ci      size_t num_workers = (opts.parallel
2803e01aa904Sopenharmony_ci			    ? std::min(opts.num_workers, compare_tasks.size())
2804e01aa904Sopenharmony_ci			    : 1);
2805e01aa904Sopenharmony_ci      assert(num_workers >= 1);
2806e01aa904Sopenharmony_ci
2807e01aa904Sopenharmony_ci      abigail::workers::queue comparison_queue(num_workers, notifier);
2808e01aa904Sopenharmony_ci
2809e01aa904Sopenharmony_ci      // Compare all the binaries, in parallel and then wait for the
2810e01aa904Sopenharmony_ci      // comparisons to complete.
2811e01aa904Sopenharmony_ci      comparison_queue.schedule_tasks(compare_tasks);
2812e01aa904Sopenharmony_ci      comparison_queue.wait_for_workers_to_complete();
2813e01aa904Sopenharmony_ci
2814e01aa904Sopenharmony_ci      // Get the set of comparison tasks that were perform and sort them.
2815e01aa904Sopenharmony_ci      queue::tasks_type& done_tasks = comparison_queue.get_completed_tasks();
2816e01aa904Sopenharmony_ci      std::sort(done_tasks.begin(), done_tasks.end(), elf_size_is_greater);
2817e01aa904Sopenharmony_ci
2818e01aa904Sopenharmony_ci      // Print the reports of the comparison to standard output.
2819e01aa904Sopenharmony_ci      for (queue::tasks_type::const_iterator i = done_tasks.begin();
2820e01aa904Sopenharmony_ci	   i != done_tasks.end();
2821e01aa904Sopenharmony_ci	   ++i)
2822e01aa904Sopenharmony_ci	{
2823e01aa904Sopenharmony_ci	  compare_task_sptr t = dynamic_pointer_cast<compare_task>(*i);
2824e01aa904Sopenharmony_ci	  cout << t->pretty_output;
2825e01aa904Sopenharmony_ci	}
2826e01aa904Sopenharmony_ci    }
2827e01aa904Sopenharmony_ci
2828e01aa904Sopenharmony_ci  // Update the count of added binaries.
2829e01aa904Sopenharmony_ci  for (map<string, elf_file_sptr>::iterator it =
2830e01aa904Sopenharmony_ci	 second_package.path_elf_file_sptr_map().begin();
2831e01aa904Sopenharmony_ci       it != second_package.path_elf_file_sptr_map().end();
2832e01aa904Sopenharmony_ci       ++it)
2833e01aa904Sopenharmony_ci    diff.added_binaries.push_back(it->second);
2834e01aa904Sopenharmony_ci
2835e01aa904Sopenharmony_ci  // Print information about removed binaries on standard output.
2836e01aa904Sopenharmony_ci  if (diff.removed_binaries.size())
2837e01aa904Sopenharmony_ci    {
2838e01aa904Sopenharmony_ci      cout << "Removed binaries:\n";
2839e01aa904Sopenharmony_ci      for (vector<elf_file_sptr>::iterator it = diff.removed_binaries.begin();
2840e01aa904Sopenharmony_ci	   it != diff.removed_binaries.end(); ++it)
2841e01aa904Sopenharmony_ci	{
2842e01aa904Sopenharmony_ci	  string relative_path;
2843e01aa904Sopenharmony_ci	  first_package.convert_path_to_relative((*it)->path, relative_path);
2844e01aa904Sopenharmony_ci	  cout << "  [D] " << relative_path << ", ";
2845e01aa904Sopenharmony_ci	  string soname;
2846e01aa904Sopenharmony_ci	  get_soname_of_elf_file((*it)->path, soname);
2847e01aa904Sopenharmony_ci	  if (!soname.empty())
2848e01aa904Sopenharmony_ci	    cout << "SONAME: " << soname;
2849e01aa904Sopenharmony_ci	  else
2850e01aa904Sopenharmony_ci	    cout << "no SONAME";
2851e01aa904Sopenharmony_ci	  cout << "\n";
2852e01aa904Sopenharmony_ci	}
2853e01aa904Sopenharmony_ci    }
2854e01aa904Sopenharmony_ci
2855e01aa904Sopenharmony_ci  // Print information about added binaries on standard output.
2856e01aa904Sopenharmony_ci  if (opts.show_added_binaries && diff.added_binaries.size())
2857e01aa904Sopenharmony_ci    {
2858e01aa904Sopenharmony_ci      cout << "Added binaries:\n";
2859e01aa904Sopenharmony_ci      for (vector<elf_file_sptr>::iterator it = diff.added_binaries.begin();
2860e01aa904Sopenharmony_ci	   it != diff.added_binaries.end(); ++it)
2861e01aa904Sopenharmony_ci	{
2862e01aa904Sopenharmony_ci	  string relative_path;
2863e01aa904Sopenharmony_ci	  second_package.convert_path_to_relative((*it)->path, relative_path);
2864e01aa904Sopenharmony_ci	  cout << "  [A] " << relative_path << ", ";
2865e01aa904Sopenharmony_ci	  string soname;
2866e01aa904Sopenharmony_ci	  get_soname_of_elf_file((*it)->path, soname);
2867e01aa904Sopenharmony_ci	  if (!soname.empty())
2868e01aa904Sopenharmony_ci	    cout << "SONAME: " << soname;
2869e01aa904Sopenharmony_ci	  else
2870e01aa904Sopenharmony_ci	    cout << "no SONAME";
2871e01aa904Sopenharmony_ci	  cout << "\n";
2872e01aa904Sopenharmony_ci	}
2873e01aa904Sopenharmony_ci    }
2874e01aa904Sopenharmony_ci
2875e01aa904Sopenharmony_ci  // Erase temporary directory tree we might have left behind.
2876e01aa904Sopenharmony_ci  maybe_erase_temp_dirs(first_package, second_package, opts);
2877e01aa904Sopenharmony_ci
2878e01aa904Sopenharmony_ci  status = notifier.status;
2879e01aa904Sopenharmony_ci
2880e01aa904Sopenharmony_ci  return status;
2881e01aa904Sopenharmony_ci}
2882e01aa904Sopenharmony_ci
2883e01aa904Sopenharmony_ci/// In the context of the unpacked content of a given package, compare
2884e01aa904Sopenharmony_ci/// the binaries inside the package against their ABIXML
2885e01aa904Sopenharmony_ci/// representation.  This should yield the empty set.
2886e01aa904Sopenharmony_ci///
2887e01aa904Sopenharmony_ci/// @param pkg (unpacked) package
2888e01aa904Sopenharmony_ci///
2889e01aa904Sopenharmony_ci/// @param diff the representation of the changes between the binaries
2890e01aa904Sopenharmony_ci/// and their ABIXML.  This should obviously be the empty set.
2891e01aa904Sopenharmony_ci///
2892e01aa904Sopenharmony_ci/// @param diff a textual representation of the diff.
2893e01aa904Sopenharmony_ci///
2894e01aa904Sopenharmony_ci/// @param opts the options provided by the user.
2895e01aa904Sopenharmony_cistatic abidiff_status
2896e01aa904Sopenharmony_ciself_compare_prepared_userspace_package(package&	pkg,
2897e01aa904Sopenharmony_ci					abi_diff&	diff,
2898e01aa904Sopenharmony_ci					options&	opts)
2899e01aa904Sopenharmony_ci{
2900e01aa904Sopenharmony_ci  abidiff_status status = abigail::tools_utils::ABIDIFF_OK;
2901e01aa904Sopenharmony_ci  abigail::workers::queue::tasks_type self_compare_tasks;
2902e01aa904Sopenharmony_ci  string pkg_name = pkg.base_name();
2903e01aa904Sopenharmony_ci
2904e01aa904Sopenharmony_ci  // Setting debug-info path of libraries
2905e01aa904Sopenharmony_ci  string debug_dir, relative_debug_path = "/usr/lib/debug/";
2906e01aa904Sopenharmony_ci  if (!pkg.debug_info_packages().empty())
2907e01aa904Sopenharmony_ci    debug_dir =
2908e01aa904Sopenharmony_ci      pkg.debug_info_packages().front()->extracted_dir_path() +
2909e01aa904Sopenharmony_ci      relative_debug_path;
2910e01aa904Sopenharmony_ci
2911e01aa904Sopenharmony_ci  suppressions_type supprs;
2912e01aa904Sopenharmony_ci  for (map<string, elf_file_sptr>::iterator it =
2913e01aa904Sopenharmony_ci	 pkg.path_elf_file_sptr_map().begin();
2914e01aa904Sopenharmony_ci       it != pkg.path_elf_file_sptr_map().end();
2915e01aa904Sopenharmony_ci       ++it)
2916e01aa904Sopenharmony_ci    {
2917e01aa904Sopenharmony_ci      if (it != pkg.path_elf_file_sptr_map().end()
2918e01aa904Sopenharmony_ci	  && (it->second->type == abigail::elf::ELF_TYPE_DSO
2919e01aa904Sopenharmony_ci	      || it->second->type == abigail::elf::ELF_TYPE_EXEC
2920e01aa904Sopenharmony_ci              || it->second->type == abigail::elf::ELF_TYPE_PI_EXEC
2921e01aa904Sopenharmony_ci	      || it->second->type == abigail::elf::ELF_TYPE_RELOCATABLE))
2922e01aa904Sopenharmony_ci	{
2923e01aa904Sopenharmony_ci	  if (it->second->type != abigail::elf::ELF_TYPE_RELOCATABLE)
2924e01aa904Sopenharmony_ci	    {
2925e01aa904Sopenharmony_ci	      compare_args_sptr args
2926e01aa904Sopenharmony_ci		(new compare_args(*it->second,
2927e01aa904Sopenharmony_ci				  debug_dir,
2928e01aa904Sopenharmony_ci				  supprs,
2929e01aa904Sopenharmony_ci				  *it->second,
2930e01aa904Sopenharmony_ci				  debug_dir,
2931e01aa904Sopenharmony_ci				  supprs,
2932e01aa904Sopenharmony_ci				  opts));
2933e01aa904Sopenharmony_ci	      self_compare_task_sptr t(new self_compare_task(args));
2934e01aa904Sopenharmony_ci	      self_compare_tasks.push_back(t);
2935e01aa904Sopenharmony_ci	    }
2936e01aa904Sopenharmony_ci	}
2937e01aa904Sopenharmony_ci    }
2938e01aa904Sopenharmony_ci
2939e01aa904Sopenharmony_ci  if (self_compare_tasks.empty())
2940e01aa904Sopenharmony_ci    {
2941e01aa904Sopenharmony_ci      maybe_erase_temp_dirs(pkg, pkg, opts);
2942e01aa904Sopenharmony_ci      return abigail::tools_utils::ABIDIFF_OK;
2943e01aa904Sopenharmony_ci    }
2944e01aa904Sopenharmony_ci
2945e01aa904Sopenharmony_ci  // Larger elfs are processed first, since it's usually safe to assume
2946e01aa904Sopenharmony_ci  // their debug-info is larger as well, but the results are still
2947e01aa904Sopenharmony_ci  // in a map ordered by looked up in elf.name order.
2948e01aa904Sopenharmony_ci  std::sort(self_compare_tasks.begin(),
2949e01aa904Sopenharmony_ci	    self_compare_tasks.end(),
2950e01aa904Sopenharmony_ci	    elf_size_is_greater);
2951e01aa904Sopenharmony_ci
2952e01aa904Sopenharmony_ci  // There's no reason to spawn more workers than there are ELF pairs
2953e01aa904Sopenharmony_ci  // to be compared.
2954e01aa904Sopenharmony_ci  size_t num_workers = (opts.parallel
2955e01aa904Sopenharmony_ci			? std::min(opts.num_workers, self_compare_tasks.size())
2956e01aa904Sopenharmony_ci			: 1);
2957e01aa904Sopenharmony_ci  assert(num_workers >= 1);
2958e01aa904Sopenharmony_ci
2959e01aa904Sopenharmony_ci  comparison_done_notify notifier(diff);
2960e01aa904Sopenharmony_ci  abigail::workers::queue comparison_queue(num_workers, notifier);
2961e01aa904Sopenharmony_ci
2962e01aa904Sopenharmony_ci  // Compare all the binaries, in parallel and then wait for the
2963e01aa904Sopenharmony_ci  // comparisons to complete.
2964e01aa904Sopenharmony_ci  comparison_queue.schedule_tasks(self_compare_tasks);
2965e01aa904Sopenharmony_ci  comparison_queue.wait_for_workers_to_complete();
2966e01aa904Sopenharmony_ci
2967e01aa904Sopenharmony_ci  // Get the set of comparison tasks that were perform and sort them.
2968e01aa904Sopenharmony_ci  queue::tasks_type& done_tasks = comparison_queue.get_completed_tasks();
2969e01aa904Sopenharmony_ci  std::sort(done_tasks.begin(), done_tasks.end(), elf_size_is_greater);
2970e01aa904Sopenharmony_ci
2971e01aa904Sopenharmony_ci  // Print the reports of the comparison to standard output.
2972e01aa904Sopenharmony_ci  for (queue::tasks_type::const_iterator i = done_tasks.begin();
2973e01aa904Sopenharmony_ci       i != done_tasks.end();
2974e01aa904Sopenharmony_ci       ++i)
2975e01aa904Sopenharmony_ci    {
2976e01aa904Sopenharmony_ci      self_compare_task_sptr t = dynamic_pointer_cast<self_compare_task>(*i);
2977e01aa904Sopenharmony_ci      if (t)
2978e01aa904Sopenharmony_ci	cout << t->pretty_output;
2979e01aa904Sopenharmony_ci    }
2980e01aa904Sopenharmony_ci
2981e01aa904Sopenharmony_ci  // Erase temporary directory tree we might have left behind.
2982e01aa904Sopenharmony_ci  maybe_erase_temp_dirs(pkg, pkg, opts);
2983e01aa904Sopenharmony_ci
2984e01aa904Sopenharmony_ci  status = notifier.status;
2985e01aa904Sopenharmony_ci
2986e01aa904Sopenharmony_ci  return status;
2987e01aa904Sopenharmony_ci}
2988e01aa904Sopenharmony_ci
2989e01aa904Sopenharmony_ci/// Compare the ABI of two prepared packages that contain linux kernel
2990e01aa904Sopenharmony_ci/// binaries.
2991e01aa904Sopenharmony_ci///
2992e01aa904Sopenharmony_ci/// A prepared package is a package which content has been extracted
2993e01aa904Sopenharmony_ci/// and mapped.
2994e01aa904Sopenharmony_ci///
2995e01aa904Sopenharmony_ci/// @param first_package the first package to consider.
2996e01aa904Sopenharmony_ci///
2997e01aa904Sopenharmony_ci/// @param second_package the second package to consider.
2998e01aa904Sopenharmony_ci///
2999e01aa904Sopenharmony_ci/// @param options the options the current program has been called
3000e01aa904Sopenharmony_ci/// with.
3001e01aa904Sopenharmony_ci///
3002e01aa904Sopenharmony_ci/// @param diff out parameter.  If this function returns true, then
3003e01aa904Sopenharmony_ci/// this parameter is set to the result of the comparison.
3004e01aa904Sopenharmony_ci///
3005e01aa904Sopenharmony_ci/// @param opts the options of the current program.
3006e01aa904Sopenharmony_ci///
3007e01aa904Sopenharmony_ci/// @return the status of the comparison.
3008e01aa904Sopenharmony_cistatic abidiff_status
3009e01aa904Sopenharmony_cicompare_prepared_linux_kernel_packages(package& first_package,
3010e01aa904Sopenharmony_ci				       package& second_package,
3011e01aa904Sopenharmony_ci				       options& opts)
3012e01aa904Sopenharmony_ci{
3013e01aa904Sopenharmony_ci  abidiff_status status = abigail::tools_utils::ABIDIFF_OK;
3014e01aa904Sopenharmony_ci  string pkg_name = first_package.base_name();
3015e01aa904Sopenharmony_ci
3016e01aa904Sopenharmony_ci  // Setting debug-info path of binaries
3017e01aa904Sopenharmony_ci  string debug_dir1, debug_dir2, relative_debug_path = "/usr/lib/debug/";
3018e01aa904Sopenharmony_ci  if (!first_package.debug_info_packages().empty()
3019e01aa904Sopenharmony_ci      && !second_package.debug_info_packages().empty())
3020e01aa904Sopenharmony_ci    {
3021e01aa904Sopenharmony_ci      debug_dir1 =
3022e01aa904Sopenharmony_ci	first_package.debug_info_packages().front()->extracted_dir_path() +
3023e01aa904Sopenharmony_ci	relative_debug_path;
3024e01aa904Sopenharmony_ci      debug_dir2 =
3025e01aa904Sopenharmony_ci	second_package.debug_info_packages().front()->extracted_dir_path() +
3026e01aa904Sopenharmony_ci	relative_debug_path;
3027e01aa904Sopenharmony_ci    }
3028e01aa904Sopenharmony_ci
3029e01aa904Sopenharmony_ci  string vmlinux_path1, vmlinux_path2;
3030e01aa904Sopenharmony_ci
3031e01aa904Sopenharmony_ci  if (!get_vmlinux_path_from_kernel_dist(debug_dir1, vmlinux_path1))
3032e01aa904Sopenharmony_ci    return abigail::tools_utils::ABIDIFF_ERROR;
3033e01aa904Sopenharmony_ci
3034e01aa904Sopenharmony_ci  if (!get_vmlinux_path_from_kernel_dist(debug_dir2, vmlinux_path2))
3035e01aa904Sopenharmony_ci    return abigail::tools_utils::ABIDIFF_ERROR;
3036e01aa904Sopenharmony_ci
3037e01aa904Sopenharmony_ci  string dist_root1 = first_package.extracted_dir_path();
3038e01aa904Sopenharmony_ci  string dist_root2 = second_package.extracted_dir_path();
3039e01aa904Sopenharmony_ci
3040e01aa904Sopenharmony_ci  abigail::ir::environment env;
3041e01aa904Sopenharmony_ci  if (opts.exported_interfaces_only.has_value())
3042e01aa904Sopenharmony_ci    env.analyze_exported_interfaces_only
3043e01aa904Sopenharmony_ci      (*opts.exported_interfaces_only);
3044e01aa904Sopenharmony_ci
3045e01aa904Sopenharmony_ci  suppressions_type supprs;
3046e01aa904Sopenharmony_ci  corpus_group_sptr corpus1, corpus2;
3047e01aa904Sopenharmony_ci  corpus1 = build_corpus_group_from_kernel_dist_under(dist_root1,
3048e01aa904Sopenharmony_ci						      debug_dir1,
3049e01aa904Sopenharmony_ci						      vmlinux_path1,
3050e01aa904Sopenharmony_ci						      opts.suppression_paths,
3051e01aa904Sopenharmony_ci						      opts.kabi_whitelist_paths,
3052e01aa904Sopenharmony_ci						      supprs,
3053e01aa904Sopenharmony_ci						      opts.verbose,
3054e01aa904Sopenharmony_ci						      env);
3055e01aa904Sopenharmony_ci
3056e01aa904Sopenharmony_ci  if (!corpus1)
3057e01aa904Sopenharmony_ci    return abigail::tools_utils::ABIDIFF_ERROR;
3058e01aa904Sopenharmony_ci
3059e01aa904Sopenharmony_ci  corpus2 = build_corpus_group_from_kernel_dist_under(dist_root2,
3060e01aa904Sopenharmony_ci						      debug_dir2,
3061e01aa904Sopenharmony_ci						      vmlinux_path2,
3062e01aa904Sopenharmony_ci						      opts.suppression_paths,
3063e01aa904Sopenharmony_ci						      opts.kabi_whitelist_paths,
3064e01aa904Sopenharmony_ci						      supprs,
3065e01aa904Sopenharmony_ci						      opts.verbose,
3066e01aa904Sopenharmony_ci						      env);
3067e01aa904Sopenharmony_ci
3068e01aa904Sopenharmony_ci  if (!corpus2)
3069e01aa904Sopenharmony_ci    return abigail::tools_utils::ABIDIFF_ERROR;
3070e01aa904Sopenharmony_ci
3071e01aa904Sopenharmony_ci  diff_context_sptr diff_ctxt(new diff_context);
3072e01aa904Sopenharmony_ci  set_diff_context_from_opts(diff_ctxt, opts);
3073e01aa904Sopenharmony_ci
3074e01aa904Sopenharmony_ci  corpus_diff_sptr diff = compute_diff(corpus1, corpus2, diff_ctxt);
3075e01aa904Sopenharmony_ci
3076e01aa904Sopenharmony_ci  if (diff->has_net_changes())
3077e01aa904Sopenharmony_ci    status |= abigail::tools_utils::ABIDIFF_ABI_CHANGE;
3078e01aa904Sopenharmony_ci  if (diff->has_incompatible_changes())
3079e01aa904Sopenharmony_ci    status |= abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE;
3080e01aa904Sopenharmony_ci
3081e01aa904Sopenharmony_ci  if (status & abigail::tools_utils::ABIDIFF_ABI_CHANGE)
3082e01aa904Sopenharmony_ci    {
3083e01aa904Sopenharmony_ci      cout << "== Kernel ABI changes between packages '"
3084e01aa904Sopenharmony_ci	   << first_package.path() << "' and '"
3085e01aa904Sopenharmony_ci	   << second_package.path() << "' are: ===\n";
3086e01aa904Sopenharmony_ci      diff->report(cout);
3087e01aa904Sopenharmony_ci      cout << "== End of kernel ABI changes between packages '"
3088e01aa904Sopenharmony_ci	   << first_package.path()
3089e01aa904Sopenharmony_ci	   << "' and '"
3090e01aa904Sopenharmony_ci	   << second_package.path() << "' ===\n\n";
3091e01aa904Sopenharmony_ci    }
3092e01aa904Sopenharmony_ci
3093e01aa904Sopenharmony_ci  return status;
3094e01aa904Sopenharmony_ci}
3095e01aa904Sopenharmony_ci
3096e01aa904Sopenharmony_ci/// Compare the ABI of two prepared packages.
3097e01aa904Sopenharmony_ci///
3098e01aa904Sopenharmony_ci/// A prepared package is a package which content has been extracted
3099e01aa904Sopenharmony_ci/// and mapped.
3100e01aa904Sopenharmony_ci///
3101e01aa904Sopenharmony_ci/// @param first_package the first package to consider.
3102e01aa904Sopenharmony_ci///
3103e01aa904Sopenharmony_ci/// @param second_package the second package to consider.
3104e01aa904Sopenharmony_ci///
3105e01aa904Sopenharmony_ci/// @param options the options the current program has been called
3106e01aa904Sopenharmony_ci/// with.
3107e01aa904Sopenharmony_ci///
3108e01aa904Sopenharmony_ci/// @param diff out parameter.  If this function returns true, then
3109e01aa904Sopenharmony_ci/// this parameter is set to the result of the comparison.
3110e01aa904Sopenharmony_ci///
3111e01aa904Sopenharmony_ci/// @param opts the options of the current program.
3112e01aa904Sopenharmony_ci///
3113e01aa904Sopenharmony_ci/// @return the status of the comparison.
3114e01aa904Sopenharmony_cistatic abidiff_status
3115e01aa904Sopenharmony_cicompare_prepared_package(package& first_package, package& second_package,
3116e01aa904Sopenharmony_ci			 abi_diff& diff, options& opts)
3117e01aa904Sopenharmony_ci{
3118e01aa904Sopenharmony_ci  abidiff_status status = abigail::tools_utils::ABIDIFF_OK;
3119e01aa904Sopenharmony_ci
3120e01aa904Sopenharmony_ci  if (abigail::tools_utils::file_is_kernel_package(first_package.base_name(),
3121e01aa904Sopenharmony_ci						   first_package.type()))
3122e01aa904Sopenharmony_ci    {
3123e01aa904Sopenharmony_ci      opts.show_symbols_not_referenced_by_debug_info = false;
3124e01aa904Sopenharmony_ci      status = compare_prepared_linux_kernel_packages(first_package,
3125e01aa904Sopenharmony_ci						      second_package,
3126e01aa904Sopenharmony_ci						      opts);
3127e01aa904Sopenharmony_ci    }
3128e01aa904Sopenharmony_ci  else
3129e01aa904Sopenharmony_ci    status = compare_prepared_userspace_packages(first_package,
3130e01aa904Sopenharmony_ci						 second_package,
3131e01aa904Sopenharmony_ci						 diff, opts);
3132e01aa904Sopenharmony_ci
3133e01aa904Sopenharmony_ci  return status;
3134e01aa904Sopenharmony_ci}
3135e01aa904Sopenharmony_ci
3136e01aa904Sopenharmony_ci/// Compare binaries in a package against their ABIXML
3137e01aa904Sopenharmony_ci/// representations.
3138e01aa904Sopenharmony_ci///
3139e01aa904Sopenharmony_ci/// @param pkg the package to consider.
3140e01aa904Sopenharmony_ci///
3141e01aa904Sopenharmony_ci/// @param diff the textual representation of the resulting
3142e01aa904Sopenharmony_ci/// comparison.
3143e01aa904Sopenharmony_ci///
3144e01aa904Sopenharmony_ci/// @param opts the options provided by the user
3145e01aa904Sopenharmony_ci///
3146e01aa904Sopenharmony_ci/// @return the status of the comparison.
3147e01aa904Sopenharmony_cistatic abidiff_status
3148e01aa904Sopenharmony_ciself_compare_prepared_package(package& pkg,
3149e01aa904Sopenharmony_ci			      abi_diff& diff,
3150e01aa904Sopenharmony_ci			      options& opts)
3151e01aa904Sopenharmony_ci{
3152e01aa904Sopenharmony_ci  abidiff_status status = abigail::tools_utils::ABIDIFF_OK;
3153e01aa904Sopenharmony_ci
3154e01aa904Sopenharmony_ci  status = self_compare_prepared_userspace_package(pkg, diff, opts);
3155e01aa904Sopenharmony_ci
3156e01aa904Sopenharmony_ci  return status;
3157e01aa904Sopenharmony_ci}
3158e01aa904Sopenharmony_ci
3159e01aa904Sopenharmony_ci/// Compare the ABI of two packages
3160e01aa904Sopenharmony_ci///
3161e01aa904Sopenharmony_ci/// @param first_package the first package to consider.
3162e01aa904Sopenharmony_ci///
3163e01aa904Sopenharmony_ci/// @param second_package the second package to consider.
3164e01aa904Sopenharmony_ci///
3165e01aa904Sopenharmony_ci/// @param options the options the current program has been called
3166e01aa904Sopenharmony_ci/// with.
3167e01aa904Sopenharmony_ci///
3168e01aa904Sopenharmony_ci/// @param diff out parameter.  If this function returns true, then
3169e01aa904Sopenharmony_ci/// this parameter is set to the result of the comparison.
3170e01aa904Sopenharmony_ci///
3171e01aa904Sopenharmony_ci/// @param opts the options of the current program.
3172e01aa904Sopenharmony_ci///
3173e01aa904Sopenharmony_ci/// @return the status of the comparison.
3174e01aa904Sopenharmony_cistatic abidiff_status
3175e01aa904Sopenharmony_cicompare(package_sptr& first_package, package_sptr& second_package,
3176e01aa904Sopenharmony_ci	abi_diff& diff, options& opts)
3177e01aa904Sopenharmony_ci{
3178e01aa904Sopenharmony_ci  // Prepare (extract and analyze the contents) the packages and their
3179e01aa904Sopenharmony_ci  // ancillary packages.
3180e01aa904Sopenharmony_ci  //
3181e01aa904Sopenharmony_ci  // Note that the package preparations happens in parallel.
3182e01aa904Sopenharmony_ci  if (!prepare_packages(first_package, second_package, opts))
3183e01aa904Sopenharmony_ci    {
3184e01aa904Sopenharmony_ci      maybe_erase_temp_dirs(*first_package, *second_package, opts);
3185e01aa904Sopenharmony_ci      return abigail::tools_utils::ABIDIFF_ERROR;
3186e01aa904Sopenharmony_ci    }
3187e01aa904Sopenharmony_ci
3188e01aa904Sopenharmony_ci  return compare_prepared_package(*first_package, *second_package, diff, opts);
3189e01aa904Sopenharmony_ci}
3190e01aa904Sopenharmony_ci
3191e01aa904Sopenharmony_ci/// Compare binaries in a package against their ABIXML
3192e01aa904Sopenharmony_ci/// representations.
3193e01aa904Sopenharmony_ci///
3194e01aa904Sopenharmony_ci/// @param pkg the package to consider.
3195e01aa904Sopenharmony_ci///
3196e01aa904Sopenharmony_ci/// @param opts the options provided by the user
3197e01aa904Sopenharmony_ci///
3198e01aa904Sopenharmony_ci/// @return the status of the comparison.
3199e01aa904Sopenharmony_cistatic abidiff_status
3200e01aa904Sopenharmony_cicompare_to_self(package_sptr& pkg, options& opts)
3201e01aa904Sopenharmony_ci{
3202e01aa904Sopenharmony_ci  if (!prepare_package(pkg, opts))
3203e01aa904Sopenharmony_ci    return abigail::tools_utils::ABIDIFF_ERROR;
3204e01aa904Sopenharmony_ci
3205e01aa904Sopenharmony_ci  abi_diff diff;
3206e01aa904Sopenharmony_ci  return self_compare_prepared_package(*pkg, diff, opts);
3207e01aa904Sopenharmony_ci}
3208e01aa904Sopenharmony_ci
3209e01aa904Sopenharmony_ci/// Compare the ABI of two packages.
3210e01aa904Sopenharmony_ci///
3211e01aa904Sopenharmony_ci/// @param first_package the first package to consider.
3212e01aa904Sopenharmony_ci///
3213e01aa904Sopenharmony_ci/// @param second_package the second package to consider.
3214e01aa904Sopenharmony_ci///
3215e01aa904Sopenharmony_ci/// @param opts the options the current program has been called with.
3216e01aa904Sopenharmony_ci///
3217e01aa904Sopenharmony_ci/// @return the status of the comparison.
3218e01aa904Sopenharmony_cistatic abidiff_status
3219e01aa904Sopenharmony_cicompare(package_sptr& first_package,
3220e01aa904Sopenharmony_ci	package_sptr& second_package,
3221e01aa904Sopenharmony_ci	options& opts)
3222e01aa904Sopenharmony_ci{
3223e01aa904Sopenharmony_ci  abi_diff diff;
3224e01aa904Sopenharmony_ci  return compare(first_package, second_package, diff, opts);
3225e01aa904Sopenharmony_ci}
3226e01aa904Sopenharmony_ci
3227e01aa904Sopenharmony_ci/// Parse the command line of the current program.
3228e01aa904Sopenharmony_ci///
3229e01aa904Sopenharmony_ci/// @param argc the number of arguments in the @p argv parameter.
3230e01aa904Sopenharmony_ci///
3231e01aa904Sopenharmony_ci/// @param argv the array of arguemnts passed to the function.  The
3232e01aa904Sopenharmony_ci/// first argument is the name of this program.
3233e01aa904Sopenharmony_ci///
3234e01aa904Sopenharmony_ci/// @param opts the resulting options.
3235e01aa904Sopenharmony_ci///
3236e01aa904Sopenharmony_ci/// @return true upon successful parsing.
3237e01aa904Sopenharmony_cistatic bool
3238e01aa904Sopenharmony_ciparse_command_line(int argc, char* argv[], options& opts)
3239e01aa904Sopenharmony_ci{
3240e01aa904Sopenharmony_ci  if (argc < 2)
3241e01aa904Sopenharmony_ci    return false;
3242e01aa904Sopenharmony_ci
3243e01aa904Sopenharmony_ci  for (int i = 1; i < argc; ++i)
3244e01aa904Sopenharmony_ci    {
3245e01aa904Sopenharmony_ci      if (argv[i][0] != '-')
3246e01aa904Sopenharmony_ci        {
3247e01aa904Sopenharmony_ci          if (opts.package1.empty())
3248e01aa904Sopenharmony_ci            {
3249e01aa904Sopenharmony_ci              opts.package1 = make_path_absolute(argv[i]).get();
3250e01aa904Sopenharmony_ci              opts.nonexistent_file = !file_exists(opts.package1);
3251e01aa904Sopenharmony_ci            }
3252e01aa904Sopenharmony_ci          else if (opts.package2.empty())
3253e01aa904Sopenharmony_ci            {
3254e01aa904Sopenharmony_ci              opts.package2 = make_path_absolute(argv[i]).get();
3255e01aa904Sopenharmony_ci              opts.nonexistent_file = !file_exists(opts.package2);
3256e01aa904Sopenharmony_ci            }
3257e01aa904Sopenharmony_ci          else
3258e01aa904Sopenharmony_ci	    {
3259e01aa904Sopenharmony_ci	      opts.wrong_arg = argv[i];
3260e01aa904Sopenharmony_ci	      return false;
3261e01aa904Sopenharmony_ci	    }
3262e01aa904Sopenharmony_ci
3263e01aa904Sopenharmony_ci          if (opts.nonexistent_file)
3264e01aa904Sopenharmony_ci            {
3265e01aa904Sopenharmony_ci              opts.wrong_option = argv[i];
3266e01aa904Sopenharmony_ci              return true;
3267e01aa904Sopenharmony_ci            }
3268e01aa904Sopenharmony_ci        }
3269e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--debug-info-pkg1")
3270e01aa904Sopenharmony_ci	       || !strcmp(argv[i], "--d1"))
3271e01aa904Sopenharmony_ci        {
3272e01aa904Sopenharmony_ci          int j = i + 1;
3273e01aa904Sopenharmony_ci          if (j >= argc)
3274e01aa904Sopenharmony_ci            {
3275e01aa904Sopenharmony_ci	      opts.missing_operand = true;
3276e01aa904Sopenharmony_ci	      opts.wrong_option = argv[i];
3277e01aa904Sopenharmony_ci	      return true;
3278e01aa904Sopenharmony_ci            }
3279e01aa904Sopenharmony_ci          opts.debug_packages1.push_back
3280e01aa904Sopenharmony_ci	    (abigail::tools_utils::make_path_absolute(argv[j]).get());
3281e01aa904Sopenharmony_ci          ++i;
3282e01aa904Sopenharmony_ci        }
3283e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--debug-info-pkg2")
3284e01aa904Sopenharmony_ci	       || !strcmp(argv[i], "--d2"))
3285e01aa904Sopenharmony_ci        {
3286e01aa904Sopenharmony_ci          int j = i + 1;
3287e01aa904Sopenharmony_ci          if (j >= argc)
3288e01aa904Sopenharmony_ci            {
3289e01aa904Sopenharmony_ci	      opts.missing_operand = true;
3290e01aa904Sopenharmony_ci	      opts.wrong_option = argv[i];
3291e01aa904Sopenharmony_ci	      return true;
3292e01aa904Sopenharmony_ci            }
3293e01aa904Sopenharmony_ci          opts.debug_packages2.push_back
3294e01aa904Sopenharmony_ci	    (abigail::tools_utils::make_path_absolute(argv[j]).get());
3295e01aa904Sopenharmony_ci          ++i;
3296e01aa904Sopenharmony_ci        }
3297e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--devel-pkg1")
3298e01aa904Sopenharmony_ci	       || !strcmp(argv[i], "--devel1"))
3299e01aa904Sopenharmony_ci        {
3300e01aa904Sopenharmony_ci          int j = i + 1;
3301e01aa904Sopenharmony_ci          if (j >= argc)
3302e01aa904Sopenharmony_ci            {
3303e01aa904Sopenharmony_ci	      opts.missing_operand = true;
3304e01aa904Sopenharmony_ci	      opts.wrong_option = argv[i];
3305e01aa904Sopenharmony_ci	      return true;
3306e01aa904Sopenharmony_ci            }
3307e01aa904Sopenharmony_ci          opts.devel_package1 =
3308e01aa904Sopenharmony_ci	    abigail::tools_utils::make_path_absolute(argv[j]).get();
3309e01aa904Sopenharmony_ci          ++i;
3310e01aa904Sopenharmony_ci        }
3311e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--devel-pkg2")
3312e01aa904Sopenharmony_ci	       || !strcmp(argv[i], "--devel2"))
3313e01aa904Sopenharmony_ci        {
3314e01aa904Sopenharmony_ci          int j = i + 1;
3315e01aa904Sopenharmony_ci          if (j >= argc)
3316e01aa904Sopenharmony_ci            {
3317e01aa904Sopenharmony_ci	      opts.missing_operand = true;
3318e01aa904Sopenharmony_ci	      opts.wrong_option = argv[i];
3319e01aa904Sopenharmony_ci	      return true;
3320e01aa904Sopenharmony_ci            }
3321e01aa904Sopenharmony_ci          opts.devel_package2 =
3322e01aa904Sopenharmony_ci	    abigail::tools_utils::make_path_absolute(argv[j]).get();
3323e01aa904Sopenharmony_ci          ++i;
3324e01aa904Sopenharmony_ci        }
3325e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--drop-private-types"))
3326e01aa904Sopenharmony_ci	opts.drop_private_types = true;
3327e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--no-default-suppression"))
3328e01aa904Sopenharmony_ci	opts.no_default_suppression = true;
3329e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--keep-tmp-files"))
3330e01aa904Sopenharmony_ci	opts.keep_tmp_files = true;
3331e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--dso-only"))
3332e01aa904Sopenharmony_ci	opts.compare_dso_only = true;
3333e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--private-dso"))
3334e01aa904Sopenharmony_ci	opts.compare_private_dsos = true;
3335e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--leaf-changes-only")
3336e01aa904Sopenharmony_ci	       ||!strcmp(argv[i], "-l"))
3337e01aa904Sopenharmony_ci	opts.leaf_changes_only = true;
3338e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--impacted-interfaces")
3339e01aa904Sopenharmony_ci	       ||!strcmp(argv[i], "-i"))
3340e01aa904Sopenharmony_ci	opts.show_impacted_interfaces = true;
3341e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--non-reachable-types")
3342e01aa904Sopenharmony_ci	       ||!strcmp(argv[i], "-t"))
3343e01aa904Sopenharmony_ci	opts.show_all_types = true;
3344e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--full-impact")
3345e01aa904Sopenharmony_ci	       ||!strcmp(argv[i], "-f"))
3346e01aa904Sopenharmony_ci	opts.show_full_impact_report = true;
3347e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--exported-interfaces-only"))
3348e01aa904Sopenharmony_ci	opts.exported_interfaces_only = true;
3349e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--allow-non-exported-interfaces"))
3350e01aa904Sopenharmony_ci	opts.exported_interfaces_only = false;
3351e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--no-linkage-name"))
3352e01aa904Sopenharmony_ci	opts.show_linkage_names = false;
3353e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--redundant"))
3354e01aa904Sopenharmony_ci	opts.show_redundant_changes = true;
3355e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--harmless"))
3356e01aa904Sopenharmony_ci	opts.show_harmless_changes = true;
3357e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--no-show-locs"))
3358e01aa904Sopenharmony_ci	opts.show_locs = false;
3359e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--show-bytes"))
3360e01aa904Sopenharmony_ci	opts.show_offsets_sizes_in_bits = false;
3361e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--show-bits"))
3362e01aa904Sopenharmony_ci	opts.show_offsets_sizes_in_bits = true;
3363e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--show-hex"))
3364e01aa904Sopenharmony_ci	opts.show_hexadecimal_values = true;
3365e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--show-dec"))
3366e01aa904Sopenharmony_ci	opts.show_hexadecimal_values = false;
3367e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--no-show-relative-offset-changes"))
3368e01aa904Sopenharmony_ci	opts.show_relative_offset_changes = false;
3369e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--no-added-syms"))
3370e01aa904Sopenharmony_ci	opts.show_added_syms = false;
3371e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--no-unreferenced-symbols"))
3372e01aa904Sopenharmony_ci	opts.show_symbols_not_referenced_by_debug_info = false;
3373e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--no-added-binaries"))
3374e01aa904Sopenharmony_ci	opts.show_added_binaries = false;
3375e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--fail-no-dbg"))
3376e01aa904Sopenharmony_ci	opts.fail_if_no_debug_info = true;
3377e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--no-leverage-dwarf-factorization"))
3378e01aa904Sopenharmony_ci	opts.leverage_dwarf_factorization = false;
3379e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--no-assume-odr-for-cplusplus"))
3380e01aa904Sopenharmony_ci	opts.assume_odr_for_cplusplus = false;
3381e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--verbose"))
3382e01aa904Sopenharmony_ci	opts.verbose = true;
3383e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--no-abignore"))
3384e01aa904Sopenharmony_ci	opts.abignore = false;
3385e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--no-parallel"))
3386e01aa904Sopenharmony_ci	opts.parallel = false;
3387e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--show-identical-binaries"))
3388e01aa904Sopenharmony_ci	opts.show_identical_binaries = true;
3389e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--self-check"))
3390e01aa904Sopenharmony_ci	opts.self_check = true;
3391e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--suppressions")
3392e01aa904Sopenharmony_ci	       || !strcmp(argv[i], "--suppr"))
3393e01aa904Sopenharmony_ci	{
3394e01aa904Sopenharmony_ci	  int j = i + 1;
3395e01aa904Sopenharmony_ci	  if (j >= argc)
3396e01aa904Sopenharmony_ci	    return false;
3397e01aa904Sopenharmony_ci	  opts.suppression_paths.push_back(argv[j]);
3398e01aa904Sopenharmony_ci	  ++i;
3399e01aa904Sopenharmony_ci	}
3400e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--linux-kernel-abi-whitelist")
3401e01aa904Sopenharmony_ci	       || !strcmp(argv[i], "-w"))
3402e01aa904Sopenharmony_ci	{
3403e01aa904Sopenharmony_ci	  int j = i + 1;
3404e01aa904Sopenharmony_ci	  if (j >= argc)
3405e01aa904Sopenharmony_ci	    {
3406e01aa904Sopenharmony_ci	      opts.missing_operand = true;
3407e01aa904Sopenharmony_ci	      opts.wrong_option = argv[i];
3408e01aa904Sopenharmony_ci	      return true;
3409e01aa904Sopenharmony_ci	    }
3410e01aa904Sopenharmony_ci	  if (guess_file_type(argv[j]) == abigail::tools_utils::FILE_TYPE_RPM)
3411e01aa904Sopenharmony_ci	    // The kernel abi whitelist is actually a whitelist
3412e01aa904Sopenharmony_ci	    // *package*.  Take that into account.
3413e01aa904Sopenharmony_ci	    opts.kabi_whitelist_packages.push_back
3414e01aa904Sopenharmony_ci	      (make_path_absolute(argv[j]).get());
3415e01aa904Sopenharmony_ci	  else
3416e01aa904Sopenharmony_ci	    // We assume the kernel abi whitelist is a white list
3417e01aa904Sopenharmony_ci	    // file.
3418e01aa904Sopenharmony_ci	    opts.kabi_whitelist_paths.push_back(argv[j]);
3419e01aa904Sopenharmony_ci	  ++i;
3420e01aa904Sopenharmony_ci	}
3421e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--wp"))
3422e01aa904Sopenharmony_ci	{
3423e01aa904Sopenharmony_ci	  int j = i + 1;
3424e01aa904Sopenharmony_ci	  if (j >= argc)
3425e01aa904Sopenharmony_ci	    {
3426e01aa904Sopenharmony_ci	      opts.missing_operand = true;
3427e01aa904Sopenharmony_ci	      opts.wrong_option = argv[i];
3428e01aa904Sopenharmony_ci	      return true;
3429e01aa904Sopenharmony_ci	    }
3430e01aa904Sopenharmony_ci	  opts.kabi_whitelist_packages.push_back
3431e01aa904Sopenharmony_ci	    (make_path_absolute(argv[j]).get());
3432e01aa904Sopenharmony_ci	  ++i;
3433e01aa904Sopenharmony_ci	}
3434e01aa904Sopenharmony_ci#ifdef WITH_CTF
3435e01aa904Sopenharmony_ci	else if (!strcmp(argv[i], "--ctf"))
3436e01aa904Sopenharmony_ci          opts.use_ctf = true;
3437e01aa904Sopenharmony_ci#endif
3438e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--help")
3439e01aa904Sopenharmony_ci	       || !strcmp(argv[i], "-h"))
3440e01aa904Sopenharmony_ci        {
3441e01aa904Sopenharmony_ci          opts.display_usage = true;
3442e01aa904Sopenharmony_ci          return true;
3443e01aa904Sopenharmony_ci        }
3444e01aa904Sopenharmony_ci      else if (!strcmp(argv[i], "--version")
3445e01aa904Sopenharmony_ci	       || !strcmp(argv[i], "-v"))
3446e01aa904Sopenharmony_ci	{
3447e01aa904Sopenharmony_ci	  opts.display_version = true;
3448e01aa904Sopenharmony_ci	  return true;
3449e01aa904Sopenharmony_ci	}
3450e01aa904Sopenharmony_ci      else
3451e01aa904Sopenharmony_ci	{
3452e01aa904Sopenharmony_ci	  if (strlen(argv[i]) >= 2 && argv[i][0] == '-' && argv[i][1] == '-')
3453e01aa904Sopenharmony_ci	    opts.wrong_option = argv[i];
3454e01aa904Sopenharmony_ci	  return false;
3455e01aa904Sopenharmony_ci	}
3456e01aa904Sopenharmony_ci    }
3457e01aa904Sopenharmony_ci
3458e01aa904Sopenharmony_ci  return true;
3459e01aa904Sopenharmony_ci}
3460e01aa904Sopenharmony_ci
3461e01aa904Sopenharmony_ciint
3462e01aa904Sopenharmony_cimain(int argc, char* argv[])
3463e01aa904Sopenharmony_ci{
3464e01aa904Sopenharmony_ci  options opts(argv[0]);
3465e01aa904Sopenharmony_ci
3466e01aa904Sopenharmony_ci  if (!parse_command_line(argc, argv, opts))
3467e01aa904Sopenharmony_ci    {
3468e01aa904Sopenharmony_ci      if (!opts.wrong_option.empty())
3469e01aa904Sopenharmony_ci	emit_prefix("abipkgdiff", cerr)
3470e01aa904Sopenharmony_ci	  << "unrecognized option: " << opts.wrong_option
3471e01aa904Sopenharmony_ci	  << "\ntry the --help option for more information\n";
3472e01aa904Sopenharmony_ci      else
3473e01aa904Sopenharmony_ci	emit_prefix("abipkgdiff", cerr)
3474e01aa904Sopenharmony_ci	  << "unrecognized argument: " << opts.wrong_arg
3475e01aa904Sopenharmony_ci	  << "\ntry the --help option for more information\n";
3476e01aa904Sopenharmony_ci      return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3477e01aa904Sopenharmony_ci	      | abigail::tools_utils::ABIDIFF_ERROR);
3478e01aa904Sopenharmony_ci    }
3479e01aa904Sopenharmony_ci
3480e01aa904Sopenharmony_ci  if (opts.missing_operand)
3481e01aa904Sopenharmony_ci    {
3482e01aa904Sopenharmony_ci      emit_prefix("abipkgdiff", cerr)
3483e01aa904Sopenharmony_ci	<< "missing operand\n"
3484e01aa904Sopenharmony_ci        "try the --help option for more information\n";
3485e01aa904Sopenharmony_ci      return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3486e01aa904Sopenharmony_ci	      | abigail::tools_utils::ABIDIFF_ERROR);
3487e01aa904Sopenharmony_ci    }
3488e01aa904Sopenharmony_ci
3489e01aa904Sopenharmony_ci  if (opts.nonexistent_file)
3490e01aa904Sopenharmony_ci    {
3491e01aa904Sopenharmony_ci      string input_file;
3492e01aa904Sopenharmony_ci      base_name(opts.wrong_option, input_file);
3493e01aa904Sopenharmony_ci      emit_prefix("abipkgdiff", cerr)
3494e01aa904Sopenharmony_ci	<< "The input file " << input_file << " doesn't exist\n"
3495e01aa904Sopenharmony_ci	"try the --help option for more information\n";
3496e01aa904Sopenharmony_ci      return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3497e01aa904Sopenharmony_ci	      | abigail::tools_utils::ABIDIFF_ERROR);
3498e01aa904Sopenharmony_ci    }
3499e01aa904Sopenharmony_ci
3500e01aa904Sopenharmony_ci  if (opts.kabi_whitelist_packages.size() > 2)
3501e01aa904Sopenharmony_ci    {
3502e01aa904Sopenharmony_ci      emit_prefix("abipkgdiff", cerr)
3503e01aa904Sopenharmony_ci	<< "no more than 2 Linux kernel white list packages can be provided\n";
3504e01aa904Sopenharmony_ci      return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3505e01aa904Sopenharmony_ci	      | abigail::tools_utils::ABIDIFF_ERROR);
3506e01aa904Sopenharmony_ci    }
3507e01aa904Sopenharmony_ci
3508e01aa904Sopenharmony_ci  if (opts.display_usage)
3509e01aa904Sopenharmony_ci    {
3510e01aa904Sopenharmony_ci      display_usage(argv[0], cout);
3511e01aa904Sopenharmony_ci      return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3512e01aa904Sopenharmony_ci	      | abigail::tools_utils::ABIDIFF_ERROR);
3513e01aa904Sopenharmony_ci    }
3514e01aa904Sopenharmony_ci
3515e01aa904Sopenharmony_ci  if (opts.display_version)
3516e01aa904Sopenharmony_ci    {
3517e01aa904Sopenharmony_ci      emit_prefix(argv[0], cout)
3518e01aa904Sopenharmony_ci	<< abigail::tools_utils::get_library_version_string()
3519e01aa904Sopenharmony_ci	<< "\n";
3520e01aa904Sopenharmony_ci      return 0;
3521e01aa904Sopenharmony_ci    }
3522e01aa904Sopenharmony_ci
3523e01aa904Sopenharmony_ci    if (!opts.no_default_suppression && opts.suppression_paths.empty())
3524e01aa904Sopenharmony_ci    {
3525e01aa904Sopenharmony_ci      // Load the default system and user suppressions.
3526e01aa904Sopenharmony_ci      string default_system_suppr_file =
3527e01aa904Sopenharmony_ci	get_default_system_suppression_file_path();
3528e01aa904Sopenharmony_ci      if (file_exists(default_system_suppr_file))
3529e01aa904Sopenharmony_ci	opts.suppression_paths.push_back(default_system_suppr_file);
3530e01aa904Sopenharmony_ci
3531e01aa904Sopenharmony_ci      string default_user_suppr_file =
3532e01aa904Sopenharmony_ci	get_default_user_suppression_file_path();
3533e01aa904Sopenharmony_ci      if (file_exists(default_user_suppr_file))
3534e01aa904Sopenharmony_ci	opts.suppression_paths.push_back(default_user_suppr_file);
3535e01aa904Sopenharmony_ci    }
3536e01aa904Sopenharmony_ci
3537e01aa904Sopenharmony_ci  if (!maybe_check_suppression_files(opts))
3538e01aa904Sopenharmony_ci    return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3539e01aa904Sopenharmony_ci	    | abigail::tools_utils::ABIDIFF_ERROR);
3540e01aa904Sopenharmony_ci
3541e01aa904Sopenharmony_ci  bool need_just_one_input_package = opts.self_check;
3542e01aa904Sopenharmony_ci
3543e01aa904Sopenharmony_ci  if (need_just_one_input_package)
3544e01aa904Sopenharmony_ci    {
3545e01aa904Sopenharmony_ci      bool bail_out = false;
3546e01aa904Sopenharmony_ci      if (!opts.package2.empty())
3547e01aa904Sopenharmony_ci	{
3548e01aa904Sopenharmony_ci	  // We don't need the second package, we'll ignore it later
3549e01aa904Sopenharmony_ci	  // down below.
3550e01aa904Sopenharmony_ci	  ;
3551e01aa904Sopenharmony_ci	}
3552e01aa904Sopenharmony_ci      if (opts.package1.empty())
3553e01aa904Sopenharmony_ci	{
3554e01aa904Sopenharmony_ci	  // We need at least one package to work with!
3555e01aa904Sopenharmony_ci	  emit_prefix("abipkgdiff", cerr)
3556e01aa904Sopenharmony_ci	    << "missing input package\n";
3557e01aa904Sopenharmony_ci	  if (bail_out)
3558e01aa904Sopenharmony_ci	    return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3559e01aa904Sopenharmony_ci		    | abigail::tools_utils::ABIDIFF_ERROR);
3560e01aa904Sopenharmony_ci	}
3561e01aa904Sopenharmony_ci    }
3562e01aa904Sopenharmony_ci  else if(opts.package1.empty() || opts.package2.empty())
3563e01aa904Sopenharmony_ci    {
3564e01aa904Sopenharmony_ci      emit_prefix("abipkgdiff", cerr)
3565e01aa904Sopenharmony_ci	<< "please enter two packages to compare" << "\n";
3566e01aa904Sopenharmony_ci      return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3567e01aa904Sopenharmony_ci	      | abigail::tools_utils::ABIDIFF_ERROR);
3568e01aa904Sopenharmony_ci    }
3569e01aa904Sopenharmony_ci
3570e01aa904Sopenharmony_ci  package_sptr first_package(new package(opts.package1, "package1"));
3571e01aa904Sopenharmony_ci
3572e01aa904Sopenharmony_ci  package_sptr second_package(new package(opts.package2, "package2"));
3573e01aa904Sopenharmony_ci  opts.pkg1 = first_package;
3574e01aa904Sopenharmony_ci  opts.pkg2 = second_package;
3575e01aa904Sopenharmony_ci
3576e01aa904Sopenharmony_ci  for (vector<string>::const_iterator p = opts.debug_packages1.begin();
3577e01aa904Sopenharmony_ci       p != opts.debug_packages1.end();
3578e01aa904Sopenharmony_ci       ++p)
3579e01aa904Sopenharmony_ci    first_package->debug_info_packages().push_back
3580e01aa904Sopenharmony_ci      (package_sptr(new package(*p,
3581e01aa904Sopenharmony_ci				"debug_package1",
3582e01aa904Sopenharmony_ci				/*pkg_kind=*/package::KIND_DEBUG_INFO)));
3583e01aa904Sopenharmony_ci
3584e01aa904Sopenharmony_ci  for (vector<string>::const_iterator p = opts.debug_packages2.begin();
3585e01aa904Sopenharmony_ci       p != opts.debug_packages2.end();
3586e01aa904Sopenharmony_ci       ++p)
3587e01aa904Sopenharmony_ci    second_package->debug_info_packages().push_back
3588e01aa904Sopenharmony_ci      (package_sptr(new package(*p,
3589e01aa904Sopenharmony_ci				"debug_package2",
3590e01aa904Sopenharmony_ci				/*pkg_kind=*/package::KIND_DEBUG_INFO)));
3591e01aa904Sopenharmony_ci
3592e01aa904Sopenharmony_ci  if (!opts.devel_package1.empty())
3593e01aa904Sopenharmony_ci    first_package->devel_package
3594e01aa904Sopenharmony_ci      (package_sptr(new package(opts.devel_package1,
3595e01aa904Sopenharmony_ci				"devel_package1",
3596e01aa904Sopenharmony_ci				/*pkg_kind=*/package::KIND_DEVEL)));
3597e01aa904Sopenharmony_ci    ;
3598e01aa904Sopenharmony_ci
3599e01aa904Sopenharmony_ci  if (!opts.devel_package2.empty())
3600e01aa904Sopenharmony_ci    second_package->devel_package
3601e01aa904Sopenharmony_ci      (package_sptr(new package(opts.devel_package2,
3602e01aa904Sopenharmony_ci				"devel_package2",
3603e01aa904Sopenharmony_ci				/*pkg_kind=*/package::KIND_DEVEL)));
3604e01aa904Sopenharmony_ci
3605e01aa904Sopenharmony_ci  if (!opts.kabi_whitelist_packages.empty())
3606e01aa904Sopenharmony_ci    {
3607e01aa904Sopenharmony_ci      first_package->kabi_whitelist_package
3608e01aa904Sopenharmony_ci	(package_sptr(new package
3609e01aa904Sopenharmony_ci		      (opts.kabi_whitelist_packages[0],
3610e01aa904Sopenharmony_ci		       "kabi_whitelist_package1",
3611e01aa904Sopenharmony_ci		       /*pkg_kind=*/package::KIND_KABI_WHITELISTS)));
3612e01aa904Sopenharmony_ci      if (opts.kabi_whitelist_packages.size() >= 2)
3613e01aa904Sopenharmony_ci	second_package->kabi_whitelist_package
3614e01aa904Sopenharmony_ci	  (package_sptr(new package
3615e01aa904Sopenharmony_ci			(opts.kabi_whitelist_packages[1],
3616e01aa904Sopenharmony_ci			 "kabi_whitelist_package2",
3617e01aa904Sopenharmony_ci			 /*pkg_kind=*/package::KIND_KABI_WHITELISTS)));
3618e01aa904Sopenharmony_ci    }
3619e01aa904Sopenharmony_ci
3620e01aa904Sopenharmony_ci  string package_name;
3621e01aa904Sopenharmony_ci  switch (first_package->type())
3622e01aa904Sopenharmony_ci    {
3623e01aa904Sopenharmony_ci    case abigail::tools_utils::FILE_TYPE_RPM:
3624e01aa904Sopenharmony_ci      if (!second_package->path().empty()
3625e01aa904Sopenharmony_ci	  && second_package->type() != abigail::tools_utils::FILE_TYPE_RPM)
3626e01aa904Sopenharmony_ci	{
3627e01aa904Sopenharmony_ci	  base_name(opts.package2, package_name);
3628e01aa904Sopenharmony_ci	  emit_prefix("abipkgdiff", cerr)
3629e01aa904Sopenharmony_ci	    << package_name << " should be an RPM file\n";
3630e01aa904Sopenharmony_ci	  return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3631e01aa904Sopenharmony_ci		  | abigail::tools_utils::ABIDIFF_ERROR);
3632e01aa904Sopenharmony_ci	}
3633e01aa904Sopenharmony_ci
3634e01aa904Sopenharmony_ci      if (file_is_kernel_package(first_package->base_name(),
3635e01aa904Sopenharmony_ci				 abigail::tools_utils::FILE_TYPE_RPM)
3636e01aa904Sopenharmony_ci	  || file_is_kernel_package(second_package->base_name(),
3637e01aa904Sopenharmony_ci				    abigail::tools_utils::FILE_TYPE_RPM))
3638e01aa904Sopenharmony_ci	{
3639e01aa904Sopenharmony_ci	  if (file_is_kernel_package(first_package->base_name(),
3640e01aa904Sopenharmony_ci				     abigail::tools_utils::FILE_TYPE_RPM)
3641e01aa904Sopenharmony_ci	      != file_is_kernel_package(second_package->base_name(),
3642e01aa904Sopenharmony_ci					abigail::tools_utils::FILE_TYPE_RPM))
3643e01aa904Sopenharmony_ci	    {
3644e01aa904Sopenharmony_ci	      emit_prefix("abipkgdiff", cerr)
3645e01aa904Sopenharmony_ci		<< "a Linux kernel package can only be compared to another "
3646e01aa904Sopenharmony_ci		"Linux kernel package\n";
3647e01aa904Sopenharmony_ci	      return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3648e01aa904Sopenharmony_ci		      | abigail::tools_utils::ABIDIFF_ERROR);
3649e01aa904Sopenharmony_ci	    }
3650e01aa904Sopenharmony_ci
3651e01aa904Sopenharmony_ci	  if (first_package->debug_info_packages().empty()
3652e01aa904Sopenharmony_ci	      || (!second_package->path().empty()
3653e01aa904Sopenharmony_ci		  && second_package->debug_info_packages().empty()))
3654e01aa904Sopenharmony_ci	    {
3655e01aa904Sopenharmony_ci	      emit_prefix("abipkgdiff", cerr)
3656e01aa904Sopenharmony_ci		<< "a Linux Kernel package must be accompanied with its "
3657e01aa904Sopenharmony_ci		"debug info package\n";
3658e01aa904Sopenharmony_ci	      return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3659e01aa904Sopenharmony_ci		      | abigail::tools_utils::ABIDIFF_ERROR);
3660e01aa904Sopenharmony_ci	    }
3661e01aa904Sopenharmony_ci	  // We are looking at kernel packages.  If the user provided
3662e01aa904Sopenharmony_ci	  // the --full-impact option then it means we want to display
3663e01aa904Sopenharmony_ci	  // the default libabigail report format where a full impact
3664e01aa904Sopenharmony_ci	  // analysis is done for each ABI change.
3665e01aa904Sopenharmony_ci	  //
3666e01aa904Sopenharmony_ci	  // Otherwise, let's just emit the leaf change report.
3667e01aa904Sopenharmony_ci	  if (opts.show_full_impact_report)
3668e01aa904Sopenharmony_ci	    opts.leaf_changes_only = false;
3669e01aa904Sopenharmony_ci	  else
3670e01aa904Sopenharmony_ci	    opts.leaf_changes_only = true;
3671e01aa904Sopenharmony_ci	}
3672e01aa904Sopenharmony_ci
3673e01aa904Sopenharmony_ci      break;
3674e01aa904Sopenharmony_ci
3675e01aa904Sopenharmony_ci    case abigail::tools_utils::FILE_TYPE_DEB:
3676e01aa904Sopenharmony_ci      if (!second_package->path().empty()
3677e01aa904Sopenharmony_ci	  && second_package->type() != abigail::tools_utils::FILE_TYPE_DEB)
3678e01aa904Sopenharmony_ci	{
3679e01aa904Sopenharmony_ci	  base_name(opts.package2, package_name);
3680e01aa904Sopenharmony_ci	  emit_prefix("abipkgdiff", cerr)
3681e01aa904Sopenharmony_ci	    << package_name << " should be a DEB file\n";
3682e01aa904Sopenharmony_ci	  return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3683e01aa904Sopenharmony_ci		  | abigail::tools_utils::ABIDIFF_ERROR);
3684e01aa904Sopenharmony_ci	}
3685e01aa904Sopenharmony_ci      break;
3686e01aa904Sopenharmony_ci
3687e01aa904Sopenharmony_ci    case abigail::tools_utils::FILE_TYPE_DIR:
3688e01aa904Sopenharmony_ci      if (!second_package->path().empty()
3689e01aa904Sopenharmony_ci	  && second_package->type() != abigail::tools_utils::FILE_TYPE_DIR)
3690e01aa904Sopenharmony_ci	{
3691e01aa904Sopenharmony_ci	  base_name(opts.package2, package_name);
3692e01aa904Sopenharmony_ci	  emit_prefix("abipkgdiff", cerr)
3693e01aa904Sopenharmony_ci	    << package_name << " should be a directory\n";
3694e01aa904Sopenharmony_ci	  return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3695e01aa904Sopenharmony_ci		  | abigail::tools_utils::ABIDIFF_ERROR);
3696e01aa904Sopenharmony_ci	}
3697e01aa904Sopenharmony_ci      break;
3698e01aa904Sopenharmony_ci
3699e01aa904Sopenharmony_ci    case abigail::tools_utils::FILE_TYPE_TAR:
3700e01aa904Sopenharmony_ci      if (!second_package->path().empty()
3701e01aa904Sopenharmony_ci	  && second_package->type() != abigail::tools_utils::FILE_TYPE_TAR)
3702e01aa904Sopenharmony_ci	{
3703e01aa904Sopenharmony_ci	  base_name(opts.package2, package_name);
3704e01aa904Sopenharmony_ci	  emit_prefix("abipkgdiff", cerr)
3705e01aa904Sopenharmony_ci	    << package_name << " should be a GNU tar archive\n";
3706e01aa904Sopenharmony_ci	  return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3707e01aa904Sopenharmony_ci		  | abigail::tools_utils::ABIDIFF_ERROR);
3708e01aa904Sopenharmony_ci	}
3709e01aa904Sopenharmony_ci      break;
3710e01aa904Sopenharmony_ci
3711e01aa904Sopenharmony_ci    default:
3712e01aa904Sopenharmony_ci      base_name(opts.package1, package_name);
3713e01aa904Sopenharmony_ci      emit_prefix("abipkgdiff", cerr)
3714e01aa904Sopenharmony_ci	<< package_name << " should be a valid package file \n";
3715e01aa904Sopenharmony_ci      return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
3716e01aa904Sopenharmony_ci	      | abigail::tools_utils::ABIDIFF_ERROR);
3717e01aa904Sopenharmony_ci    }
3718e01aa904Sopenharmony_ci
3719e01aa904Sopenharmony_ci  if (opts.self_check)
3720e01aa904Sopenharmony_ci    return compare_to_self(first_package, opts);
3721e01aa904Sopenharmony_ci
3722e01aa904Sopenharmony_ci  return compare(first_package, second_package, opts);
3723e01aa904Sopenharmony_ci}
3724