// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -*- Mode: C++ -*- // // Copyright (C) 2022 Red Hat, Inc. // // Author: Dodji Seketeli /// @file /// /// This file contains the definitions of the the fe_iface base type. #include "abg-internal.h" // ABG_BEGIN_EXPORT_DECLARATIONS #include "abg-corpus.h" #include "abg-fe-iface.h" ABG_END_EXPORT_DECLARATIONS // namespace abigail { /// The private data structure for the @ref fe_iface type. struct fe_iface::priv { std::string corpus_path; std::string dt_soname; fe_iface::options_type options; suppr::suppressions_type suppressions; ir::corpus_sptr corpus; ir::corpus_group_sptr corpus_group; priv(const std::string& path, environment& e) : corpus_path(path), options(e) { initialize(); } /// This function resets the data of @ref fe_iface::priv data so /// that it can be re-used again. void initialize() { //TODO: initialize the options. corpus_path.clear(); dt_soname.clear(); suppressions.clear(); corpus_group.reset(); } }; //end struct fe_iface::priv /// Constructor of the type @ref fe_iface::options_type. /// /// @param e the environment used by the Front End Interface. fe_iface::options_type::options_type(environment& e) : env(e) { } /// Constructor of the type @ref fe_iface. /// /// @param corpus_path the path to the file represented by the ABI /// corpus that is going to be built by this Front End. /// /// @param e the environment in which the Front End operates. fe_iface::fe_iface(const std::string& corpus_path, environment& e) : priv_(new priv(corpus_path, e)) { } /// Desctructor of the Front End Interface. fe_iface::~fe_iface() {delete priv_;} /// Re-initialize the current Front End. /// /// @param corpus_path the path to the file for which a new corpus is /// to be created. /// /// @param e the environment in which the Front End operates. void fe_iface::reset(const std::string& corpus_path, environment& e) { delete priv_; priv_ = new fe_iface::priv(corpus_path, e); } /// Getter of the the options of the current Front End Interface. /// /// @return the options of the current Front End Interface. const fe_iface::options_type& fe_iface::options() const {return priv_->options;} /// Getter of the the options of the current Front End Interface. /// /// @return the options of the current Front End Interface. fe_iface::options_type& fe_iface::options() {return priv_->options;} /// Getter of the path to the file which an ABI corpus is to be /// created for. /// /// @return the path to the file which an ABI corpus is to be created /// for. const std::string& fe_iface::corpus_path() const {return priv_->corpus_path;} /// Setter of the path to the file which an ABI corpus is to be /// created for. /// /// @param p the new path to the file which an ABI corpus is to be /// created for. void fe_iface::corpus_path(const std::string& p) {priv_->corpus_path = p;} /// Getter for the SONAME of the analyzed binary. /// /// @return the SONAME of the analyzed binary. const string& fe_iface::dt_soname() const {return priv_->dt_soname;} /// Getter for the SONAME of the analyzed binary. /// /// @return the SONAME of the analyzed binary. void fe_iface::dt_soname(const string& soname) {priv_->dt_soname = soname;} /// Test if the input binary is to be considered as a Linux Kernel /// binary. /// /// @return true iff the input binary is to be considered as a Linux /// Kernel binary. bool fe_iface::load_in_linux_kernel_mode() const {return priv_->options.load_in_linux_kernel_mode;} /// Getter of the vector of suppression specifications associated with /// the current front-end. /// /// @return the vector of suppression specifications associated with /// the current front-end. suppr::suppressions_type& fe_iface::suppressions() {return priv_->suppressions;} /// Getter of the vector of suppression specifications associated with /// the current front-end. /// /// @return the vector of suppression specifications associated with /// the current front-end. const suppr::suppressions_type& fe_iface::suppressions() const {return priv_->suppressions;} /// Setter of the vector of suppression specifications associated with /// the current front-end. /// /// @param supprs the new vector of suppression specifications /// associated with the current front-end. void fe_iface::suppressions(suppr::suppressions_type& supprs) {priv_->suppressions = supprs;} /// Add suppressions specifications to the set of suppressions to be /// used during the construction of the ABI internal representation /// (the ABI corpus) from the input file. /// /// During the construction of the ABI corpus, ABI artifacts that /// match a given suppression specification are dropped on the floor; /// that is, they are discarded and won't be part of the final ABI /// corpus. This is a way to reduce the amount of data held by the /// final ABI corpus. /// /// Note that the suppression specifications provided to this function /// are only considered during the construction of the ABI corpus. /// For instance, they are not taken into account during e.g /// comparisons of two ABI corpora that might happen later. If you /// want to apply suppression specificatins to the comparison (or /// reporting) of ABI corpora please refer to the documentation of the /// @ref diff_context type to learn how to set suppressions that are /// to be used in that context. /// /// @param supprs the suppression specifications to be applied during /// the construction of the ABI corpus. void fe_iface::add_suppressions(const suppr::suppressions_type& supprs) { for (const auto& s : supprs) if (s->get_drops_artifact_from_ir()) suppressions().push_back(s); } /// Getter for the ABI corpus being built by the current front-end. /// /// @return the ABI corpus being built by the current front-end. corpus_sptr fe_iface::corpus() { if (!priv_->corpus) { priv_->corpus = std::make_shared(options().env, corpus_path()); } return priv_->corpus; } /// Getter for the ABI corpus being built by the current front-end. /// /// @return the ABI corpus being built by the current front-end. const corpus_sptr fe_iface::corpus() const {return const_cast(this)->corpus();} /// Getter for the ABI corpus group being built by the current front-end. /// /// @return the ABI corpus group being built by the current front-end. corpus_group_sptr& fe_iface::corpus_group() {return priv_->corpus_group;} /// Getter for the ABI corpus group being built by the current front-end. /// /// @return the ABI corpus group being built by the current front-end. const corpus_group_sptr& fe_iface::corpus_group() const {return const_cast(this)->corpus_group();} /// Setter for the ABI corpus group being built by the current /// front-end. /// /// @param cg the new ABI corpus group being built by the current /// front-end. void fe_iface::corpus_group(const ir::corpus_group_sptr& cg) {priv_->corpus_group = cg;} /// Test if there is a corpus group being built. /// /// @return if there is a corpus group being built, false otherwise. bool fe_iface::has_corpus_group() const {return bool(corpus_group());} /// Return the main corpus from the current corpus group, if any. /// /// @return the main corpus of the current corpus group, if any, nil /// if no corpus group is being constructed. corpus_sptr fe_iface::main_corpus_from_current_group() { if (corpus_group()) return corpus_group()->get_main_corpus(); return corpus_sptr(); } /// Test if the current corpus being built is the main corpus of the /// current corpus group. /// /// @return return true iff the current corpus being built is the /// main corpus of the current corpus group. bool fe_iface::current_corpus_is_main_corpus_from_current_group() { corpus_sptr main_corpus = main_corpus_from_current_group(); if (main_corpus.get() == corpus().get()) return true; return false; } /// Return true if the current corpus is part of a corpus group /// being built and if it's not the main corpus of the group. /// /// For instance, this would return true if we are loading a linux /// kernel *module* that is part of the current corpus group that is /// being built. In this case, it means we should re-use types /// coming from the "vmlinux" binary that is the main corpus of the /// group. /// /// @return the corpus group the current corpus belongs to, if the /// current corpus is part of a corpus group being built. Nil otherwise. corpus_sptr fe_iface::should_reuse_type_from_corpus_group() { if (has_corpus_group()) if (corpus_sptr main_corpus = main_corpus_from_current_group()) if (!current_corpus_is_main_corpus_from_current_group()) return corpus_group(); return corpus_sptr(); } /// Try and add the representation of the ABI of a function to the set /// of exported declarations of the current corpus. /// /// @param fn the internal representation of the ABI of a function. void fe_iface::maybe_add_fn_to_exported_decls(const function_decl* fn) { if (fn) if (corpus::exported_decls_builder* b = corpus()->get_exported_decls_builder().get()) b->maybe_add_fn_to_exported_fns(fn); } /// Try and add the representation of the ABI of a variable to the set /// of exported declarations of the current corpus. /// /// @param var the internal representation of the ABI of a variable. void fe_iface::maybe_add_var_to_exported_decls(const var_decl* var) { if (var) if (corpus::exported_decls_builder* b = corpus()->get_exported_decls_builder().get()) b->maybe_add_var_to_exported_vars(var); } /// The bitwise OR operator for the @ref fe_iface::status type. /// /// @param l the left-hand side operand. /// /// @param r the right-hand side operand. /// /// @return the result of the operation. fe_iface::status operator|(fe_iface::status l, fe_iface::status r) { return static_cast(static_cast(l) | static_cast(r)); } /// The bitwise AND operator for the @ref fe_iface::status type. /// /// @param l the left-hand side operand. /// /// @param r the right-hand side operand. /// /// @return the result of the operation. fe_iface::status operator&(fe_iface::status l, fe_iface::status r) { return static_cast(static_cast(l) & static_cast(r)); } /// The bitwise |= operator for the @ref fe_iface::status type. /// /// @param l the left-hand side operand. /// /// @param r the right-hand side operand. /// /// @return the result of the operation. fe_iface::status& operator|=(fe_iface::status& l, fe_iface::status r) { l = l | r; return l; } /// The bitwise &= operator for the @ref fe_iface::status type. /// /// @param l the left-hand side operand. /// /// @param r the right-hand side operand. /// /// @return the result of the operation. fe_iface::status& operator&=(fe_iface::status& l, fe_iface::status r) { l = l & r; return l; } /// Return a diagnostic status with english sentences to describe the /// problems encoded in a given abigail::elf_reader::status, if /// there is an error. /// /// @param status the status to diagnose /// /// @return a string containing sentences that describe the possible /// errors encoded in @p s. If there is no error to encode, then the /// empty string is returned. std::string status_to_diagnostic_string(fe_iface::status s) { std::string str; if (s & fe_iface::STATUS_DEBUG_INFO_NOT_FOUND) str += "could not find debug info\n"; if (s & fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND) str += "could not find alternate debug info\n"; if (s & fe_iface::STATUS_NO_SYMBOLS_FOUND) str += "could not load ELF symbols\n"; return str; } }// namespace abigail