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