@@ -201,6 +201,12 @@ AC_ARG_ENABLE(ctf,
ENABLE_CTF=$enableval,
ENABLE_CTF=auto)
+dnl check if user has enabled BTF code
+AC_ARG_ENABLE(btf,
+ AS_HELP_STRING([--enable-btf=yes|no],
+ [disable support of btf files)]),
+ ENABLE_BTF=$enableval,
+ ENABLE_BTF=auto)
dnl *************************************************
dnl check for dependencies
dnl *************************************************
@@ -339,6 +345,77 @@ if test x$ENABLE_CTF != xno; then
fi
fi
+dnl configure BTF usage
+BPF_LIBS=
+if test x$ENABLE_BTF != xno; then
+ AC_CHECK_HEADER([bpf/btf.h],
+ [ENABLE_BTF=yes],
+ [AC_MSG_NOTICE([could not find bpf/btf.h])])
+ if test x$ENABLE_BTF = xyes; then
+ AC_MSG_NOTICE([enable BTF support])
+ ENABLE_BTF=yes
+ AC_DEFINE([WITH_BTF], 1,
+ [Defined if user enabled BTF usage])
+ BPF_LIBS=-lbpf
+ else
+ AC_MSG_NOTICE([BTF support was disabled])
+ ENABLE_BTF=no
+ fi
+
+dnl Test if various functions and structs are present.
+
+ if test x$ENABLE_BTF = xyes; then
+ dnl Test if struct btf_enum64 is present.
+ AC_CHECK_TYPE([struct btf_enum64],
+ [HAVE_BTF_ENUM64=yes],
+ [HAVE_BTF_ENUM64=no],
+ [#include <bpf/btf.h>])
+
+ if test x$HAVE_BTF_ENUM64 = xyes; then
+ AC_DEFINE([WITH_BTF_ENUM64], 1, [struct btf_enum64 is present])
+ fi
+
+ dnl Test if btf__get_nr_types is present
+ AC_CHECK_DECL([btf__get_nr_types],
+ [HAVE_BTF__GET_NR_TYPES=yes],
+ [HAVE_BTF__GET_NR_TYPES=no],
+ [#include <bpf/btf.h>])
+
+ if test x$HAVE_BTF__GET_NR_TYPES = xyes; then
+ AC_DEFINE(WITH_BTF__GET_NR_TYPES, 1, [The function btf__get_nr_types is present])
+ fi
+
+ dnl Test if btf__type_cnt is present
+ AC_CHECK_DECL([btf__type_cnt],
+ [HAVE_BTF__TYPE_CNT=yes],
+ [HAVE_BTF__TYPE_CNT=no],
+ [#include <bpf/btf.h>])
+ if test x$HAVE_BTF__TYPE_CNT = xyes; then
+ AC_DEFINE(WITH_BTF__TYPE_CNT, 1, [The function btf__type_cnt is present])
+ fi
+
+ dnl Test if BTF_KIND_TYPE_TAG exists
+ AC_CHECK_DECL([int kind = BTF_KIND_TYPE_TAG],
+ [HAVE_BTF_KIND_TYPE_TAG=yes],
+ [HAVE_BTF_KIND_TYPE_TAG=no],
+ [#include <bpf/btf.h>])
+ if test x$HAVE_BTF_KIND_TYPE_TAG = xyes; then
+ AC_DEFINE([WITH_BTF_KIND_TYPE_TAG], 1,
+ [The BTF_KIND_TYPE_TAG enumerator is present])
+ fi
+
+ dnl Test if BTF_KIND_DECL_TAG exists
+ AC_CHECK_DECL([int kind = BTF_KIND_DECL_TAG],
+ [HAVE_BTF_KIND_DECL_TAG=yes],
+ [HAVE_BTF_KIND_DECL_TAG=no],
+ [#include <bpf/btf.h>])
+ if test x$HAVE_BTF_KIND_DECL_TAG = xyes; then
+ AC_DEFINE([WITH_BTF_KIND_DECL_TAG], 1,
+ [The BTF_KIND_DECL_TAG enumerator is present])
+ fi
+ fi
+fi
+
dnl Check for dependency: libxml
LIBXML2_VERSION=2.6.22
PKG_CHECK_MODULES(XML, libxml-2.0 >= $LIBXML2_VERSION)
@@ -741,7 +818,7 @@ AX_VALGRIND_CHECK
dnl Set the list of libraries libabigail depends on
-DEPS_LIBS="$XML_LIBS $ELF_LIBS $DW_LIBS $CTF_LIBS"
+DEPS_LIBS="$XML_LIBS $ELF_LIBS $DW_LIBS $CTF_LIBS $BPF_LIBS"
AC_SUBST(DEPS_LIBS)
if test x$ABIGAIL_DEVEL != x; then
@@ -782,6 +859,7 @@ fi
dnl Set a few Automake conditionals
AM_CONDITIONAL([CTF_READER],[test "x$ENABLE_CTF" = "xyes"])
+AM_CONDITIONAL([BTF_READER],[test "x$ENABLE_BTF" = "xyes"])
dnl Set the level of C++ standard we use.
CXXFLAGS="$CXXFLAGS -std=$CXX_STANDARD"
@@ -1092,6 +1170,7 @@ AC_MSG_NOTICE([
Enable fedabipkgdiff : ${ENABLE_FEDABIPKGDIFF}
Enable python 3 : ${ENABLE_PYTHON3}
Enable CTF front-end : ${ENABLE_CTF}
+ Enable BTF front-end : ${ENABLE_BTF}
Enable running tests under Valgrind : ${enable_valgrind}
Enable build with -fsanitize=address : ${ENABLE_ASAN}
Enable build with -fsanitize=memory : ${ENABLE_MSAN}
@@ -16,8 +16,9 @@ For a comprehensive ABI change report between two input shared
libraries that includes changes about function and variable sub-types,
``abidiff`` uses by default, debug information in `DWARF`_ format, if
present, otherwise it compares interfaces using debug information in
-`CTF`_ format, if present, finally, if neither is found, it uses only
-`ELF`_ symbols to report which of them were added or removed.
+`CTF`_ or `BTF`_ formats, if present. Finally, if no debug info in
+these formats is found, it only considers `ELF`_ symbols and report
+about their addition or removal.
.. include:: tools-use-libabigail.txt
@@ -605,6 +606,11 @@ Options
When comparing binaries, extract ABI information from `CTF`_ debug
information, if present.
+ * ``--btf``
+
+ When comparing binaries, extract ABI information from `BTF`_ debug
+ information, if present.
+
* ``--stats``
Emit statistics about various internal things.
@@ -830,6 +836,7 @@ Usage examples
.. _ELF: http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
.. _DWARF: http://www.dwarfstd.org
.. _CTF: https://raw.githubusercontent.com/wiki/oracle/binutils-gdb/files/ctf-spec.pdf
+.. _BTF: https://docs.kernel.org/bpf/btf.html
.. _ODR: https://en.wikipedia.org/wiki/One_Definition_Rule
.. _One Definition Rule: https://en.wikipedia.org/wiki/One_Definition_Rule
.. _DWZ: https://sourceware.org/dwz
@@ -21,10 +21,10 @@ functions and variables, along with a complete representation of their
types.
To generate either ABI or KMI representation, by default ``abidw``
-uses debug information in `DWARF`_ format, if present, otherwise it
-looks for debug information in `CTF`_ format, if present, finally, if
-neither is found, it uses only `ELF`_ symbols to report which of them
-were added or removed.
+uses debug information in the `DWARF`_ format, if present, otherwise
+it looks for debug information in `CTF`_ or `BTF`_formats, if present.
+Finally, if no debug info in these formats is found, it only considers
+`ELF`_ symbols and report about their addition or removal.
.. include:: tools-use-libabigail.txt
@@ -389,6 +389,7 @@ standard `here
.. _GNU: http://www.gnu.org
.. _Linux Kernel: https://kernel.org/
.. _CTF: https://raw.githubusercontent.com/wiki/oracle/binutils-gdb/files/ctf-spec.pdf
+.. _BTF: https://docs.kernel.org/bpf/btf.html
.. _ODR: https://en.wikipedia.org/wiki/One_Definition_Rule
.. _One Definition Rule: https://en.wikipedia.org/wiki/One_Definition_Rule
.. _DWZ: https://sourceware.org/dwz
@@ -13,17 +13,17 @@ binaries.
For a comprehensive ABI change report that includes changes about
function and variable sub-types, the two input packages must be
accompanied with their debug information packages that contain debug
-information either in `DWARF`_ or in `CTF`_ formats. Please note
-however that some packages contain binaries that embed the debug
+information either in `DWARF`_, `CTF`_ or in `BTF`_ formats. Please
+note however that some packages contain binaries that embed the debug
information directly in a section of said binaries. In those cases,
obviously, no separate debug information package is needed as the tool
will find the debug information inside the binaries.
By default, ``abipkgdiff`` uses debug information in `DWARF`_ format,
if present, otherwise it compares binaries interfaces using debug
-information in `CTF`_ format, if present, finally, if neither is
-found, it uses only `ELF`_ symbols to report which of them were added
-or removed.
+information in `CTF`_ or in `BTF`_ formats, if present. Finally, if no
+debug info in these formats is found, it only considers `ELF`_ symbols
+and report about their addition or removal.
.. include:: tools-use-libabigail.txt
@@ -554,6 +554,11 @@ Options
This is used to compare packages with `CTF`_ debug information,
if present.
+ * ``--btf``
+
+ This is used to compare packages with `BTF`_ debug information,
+ if present.
+
.. _abipkgdiff_return_value_label:
Return value
@@ -573,6 +578,7 @@ In the later case, the value of the exit code is the same as for the
.. _tar: https://en.wikipedia.org/wiki/Tar_%28computing%29
.. _DWARF: http://www.dwarfstd.org
.. _CTF: https://raw.githubusercontent.com/wiki/oracle/binutils-gdb/files/ctf-spec.pdf
+.. _BTF: https://docs.kernel.org/bpf/btf.html
.. _Development Package: https://fedoraproject.org/wiki/Packaging:Guidelines?rd=Packaging/Guidelines#Devel_Packages
.. _ODR: https://en.wikipedia.org/wiki/One_Definition_Rule
.. _One Definition Rule: https://en.wikipedia.org/wiki/One_Definition_Rule
@@ -74,10 +74,11 @@ functions and variables) between the Kernel and its modules. In
practice, though, some users might want to compare a subset of the
those interfaces.
-By default, ``kmidiff`` uses debug information in `DWARF`_ format,
-if present, otherwise it compares interfaces using debug information
-in `CTF`_ format, if present, finally, if neither is found, it uses
-only `ELF`_ symbols to report which were added or removed.
+By default, ``kmidiff`` uses debug information in the `DWARF`_ debug
+info format, if present, otherwise it compares interfaces using `CTF`_
+or `BTF`_ debug info formats, if present. Finally, if no debug info
+in these formats is found, it only considers `ELF`_ symbols and report
+about their addition or removal.
Users can then define a "white list" of the interfaces to compare.
Such a white list is a just a file in the "INI" format that looks
@@ -179,8 +180,13 @@ Options
* ``--ctf``
- Extract ABI information from `CTF`_ debug information, if present in
- the Kernel and Modules.
+ Extract ABI information from `CTF`_ debug information, if present,
+ in the Kernel and Modules.
+
+ * ``--btf``
+
+ Extract ABI information from `BTF`_ debug information, if present,
+ in the Kernel and Modules.
* ``--impacted-interfaces | -i``
@@ -249,3 +255,4 @@ Options
.. _Linux Kernel: https://kernel.org
.. _DWARF: http://www.dwarfstd.org
.. _CTF: https://raw.githubusercontent.com/wiki/oracle/binutils-gdb/files/ctf-spec.pdf
+.. _BTF: https://docs.kernel.org/bpf/btf.html
@@ -34,4 +34,8 @@ if CTF_READER
pkginclude_HEADERS += abg-ctf-reader.h
endif
+if BTF_READER
+pkginclude_HEADERS += abg-btf-reader.h
+endif
+
EXTRA_DIST = abg-version.h.in
new file mode 100644
@@ -0,0 +1,34 @@
+// 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 declarations of the front-end to analyze the
+/// BTF information contained in an ELF file.
+
+#ifndef __ABG_BTF_READER_H__
+#define __ABG_BTF_READER_H__
+
+#include "abg-elf-based-reader.h"
+
+namespace abigail
+{
+
+namespace btf
+{
+
+elf_based_reader_sptr
+create_reader(const std::string& elf_path,
+ const vector<char**>& debug_info_root_paths,
+ environment& env,
+ bool load_all_types = false,
+ bool linux_kernel_mode = false);
+
+}//end namespace btf
+}//end namespace abigail
+
+#endif //__ABG_BTF_READER_H__
@@ -48,7 +48,8 @@ public:
ELF_ORIGIN = 1 << 1,
DWARF_ORIGIN = 1 << 2,
CTF_ORIGIN = 1 << 3,
- LINUX_KERNEL_BINARY_ORIGIN = 1 << 4
+ BTF_ORIGIN = 1 << 4,
+ LINUX_KERNEL_BINARY_ORIGIN = 1 << 5
};
private:
@@ -97,6 +97,9 @@ class reader : public fe_iface
bool
has_ctf_debug_info() const;
+ bool
+ has_btf_debug_info() const;
+
const Dwarf*
alternate_dwarf_debug_info() const;
@@ -118,6 +121,9 @@ class reader : public fe_iface
const Elf_Scn*
find_alternate_ctf_section() const;
+ const Elf_Scn*
+ find_btf_section() const;
+
const vector<string>&
dt_needed()const;
@@ -41,6 +41,8 @@ bool file_has_dwarf_debug_info(const string& elf_file_path,
const vector<char**>& debug_info_root_paths);
bool file_has_ctf_debug_info(const string& elf_file_path,
const vector<char**>& debug_info_root_paths);
+bool file_has_btf_debug_info(const string& elf_file_path,
+ const vector<char**>& debug_info_root_paths);
bool is_dir(const string&);
bool dir_exists(const string&);
bool dir_is_empty(const string &);
@@ -48,6 +48,10 @@ if CTF_READER
libabigail_la_SOURCES += abg-ctf-reader.cc
endif
+if BTF_READER
+libabigail_la_SOURCES += abg-btf-reader.cc
+endif
+
libabigail_la_LIBADD = $(DEPS_LIBS) $(FTS_LIBS)
libabigail_la_LDFLAGS = -lpthread -Wl,--as-needed -no-undefined -version-info $(LIBABIGAIL_SO_CURRENT):$(LIBABIGAIL_SO_REVISION):$(LIBABIGAIL_SO_AGE)
new file mode 100644
@@ -0,0 +1,1102 @@
+// 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 front-end to analyze the
+/// BTF information contained in an ELF file.
+
+#include "abg-internal.h"
+
+#ifdef WITH_BTF
+
+#include <bpf/btf.h>
+#include <iostream>
+#include <unordered_map>
+
+#include "abg-elf-helpers.h"
+
+// <headers defining libabigail's API go under here>
+ABG_BEGIN_EXPORT_DECLARATIONS
+
+#include "abg-btf-reader.h"
+#include "abg-ir.h"
+#include "abg-tools-utils.h"
+
+ABG_END_EXPORT_DECLARATIONS
+// </headers defining libabigail's API>
+
+namespace abigail
+{
+using namespace ir;
+
+namespace btf
+{
+
+class reader;
+
+/// A convenience typedef for a shared pointer to
+/// abigail::btf::reader.
+typedef shared_ptr<reader> reader_sptr;
+
+static const char*
+btf_offset_to_string(const ::btf* btf, uint32_t offset)
+{
+ if (!offset)
+ return "__anonymous__";
+ return btf__name_by_offset(btf, offset) ?: "(invalid string offset)";
+}
+
+/// A convenience typedef of a map that associates a btf type id to a
+/// libabigail ABI artifact.
+typedef std::unordered_map<int, type_or_decl_base_sptr>
+btf_type_id_to_abi_artifact_map_type;
+
+/// The BTF front-end abstraction type.
+class reader : public elf_based_reader
+{
+ ::btf* btf_handle_ = nullptr;
+ translation_unit_sptr cur_tu_;
+ vector<type_base_sptr> types_to_canonicalize_;
+ btf_type_id_to_abi_artifact_map_type btf_type_id_to_artifacts_;
+
+ /// Getter of the handle to the BTF data as returned by libbpf.
+ ///
+ /// @return the handle to the BTF data as returned by libbpf.
+ ::btf*
+ btf_handle()
+ {
+ if (btf_handle_ == nullptr)
+ {
+ btf_handle_ = btf__parse(corpus_path().c_str(), nullptr);
+ if (!btf_handle_)
+ std::cerr << "Could not parse BTF information from file '"
+ << corpus_path().c_str() << "'" << std::endl;
+ }
+ return btf_handle_;
+ }
+
+ /// Getter of the environment of the current front-end.
+ ///
+ /// @return The environment of the current front-end.
+ environment&
+ env()
+ {return options().env;}
+
+ /// Getter of the environment of the current front-end.
+ ///
+ /// @return The environment of the current front-end.
+ const environment&
+ env() const
+ {return const_cast<reader*>(this)->env();}
+
+ /// Getter of the current translation unit being built.
+ ///
+ /// Actually, BTF doesn't keep track of the translation unit each
+ /// ABI artifact originates from. So an "artificial" translation
+ /// unit is built. It contains all the ABI artifacts of the binary.
+ ///
+ /// @return The current translation unit being built.
+ translation_unit_sptr&
+ cur_tu()
+ {return cur_tu_;}
+
+ /// Getter of the current translation unit being built.
+ ///
+ /// Actually, BTF doesn't keep track of the translation unit each
+ /// ABI artifact originates from. So an "artificial" translation
+ /// unit is built. It contains all the ABI artifacts of the binary.
+ ///
+ /// @return The current translation unit being built.
+ const translation_unit_sptr&
+ cur_tu() const
+ {return cur_tu_;}
+
+ /// Getter of the current translation unit being built.
+ ///
+ /// Actually, BTF doesn't keep track of the translation unit each
+ /// ABI artifact originates from. So an "artificial" translation
+ /// unit is built. It contains all the ABI artifacts of the binary.
+ ///
+ /// @return The current translation unit being built.
+ void
+ cur_tu(const translation_unit_sptr& tu)
+ {cur_tu_ = tu;}
+
+ /// Getter of the map that associates a BTF type ID to an ABI
+ /// artifact.
+ ///
+ /// @return The map that associates a BTF type ID to an ABI
+ /// artifact.
+ btf_type_id_to_abi_artifact_map_type&
+ btf_type_id_to_artifacts()
+ {return btf_type_id_to_artifacts_;}
+
+ /// Getter of the map that associates a BTF type ID to an ABI
+ /// artifact.
+ ///
+ /// @return The map that associates a BTF type ID to an ABI
+ /// artifact.
+ const btf_type_id_to_abi_artifact_map_type&
+ btf_type_id_to_artifacts() const
+ {return btf_type_id_to_artifacts_;}
+
+ /// Get the ABI artifact that is associated to a given BTF type ID.
+ ///
+ /// If no ABI artifact is associated to the BTF type id, then return
+ /// nil.
+ ///
+ /// @return the ABI artifact that is associated to a given BTF type
+ /// id.
+ type_or_decl_base_sptr
+ lookup_artifact_from_btf_id(int btf_id)
+ {
+ auto i = btf_type_id_to_artifacts().find(btf_id);
+ if (i != btf_type_id_to_artifacts().end())
+ return i->second;
+ return type_or_decl_base_sptr();
+ }
+
+ /// Associate an ABI artifact to a given BTF type ID.
+ ///
+ /// @param artifact the ABI artifact to consider.
+ ///
+ /// @param btf_type_id the BTF type ID to associate to @p artifact.
+ void
+ associate_artifact_to_btf_type_id(const type_or_decl_base_sptr& artifact,
+ int btf_type_id)
+ {btf_type_id_to_artifacts()[btf_type_id] = artifact;}
+
+ /// Schecule a type for canonicalization at the end of the debug
+ /// info loading.
+ ///
+ /// @param t the type to schedule.
+ void
+ schedule_type_for_canonocalization(const type_base_sptr& t)
+ {types_to_canonicalize_.push_back(t);}
+
+ /// Canonicalize all the types scheduled for canonicalization using
+ /// schedule_type_for_canonocalization().
+ void
+ canonicalize_types()
+ {
+ for (auto t : types_to_canonicalize_)
+ canonicalize(t);
+ }
+
+ uint64_t
+ nr_btf_types() const
+ {
+#ifdef WITH_BTF__GET_NR_TYPES
+#define GET_NB_TYPES btf__get_nr_types
+#endif
+
+#ifdef WITH_BTF__TYPE_CNT
+#undef GET_NB_TYPES
+#define GET_NB_TYPES btf__type_cnt
+#endif
+
+#ifndef GET_NB_TYPES
+ ABG_ASSERT_NOT_REACHED;
+ return 0;
+#endif
+
+ return GET_NB_TYPES(const_cast<reader*>(this)->btf_handle());
+ }
+
+protected:
+ reader() = delete;
+
+ /// Initializer of the current instance of @ref btf::reader.
+ ///
+ /// This frees the resources used by the current instance of @ref
+ /// btf::reader and gets it ready to analyze another ELF
+ /// file.
+ ///
+ /// @param elf_path the path to the ELF file to read from.
+ ///
+ /// @param debug_info_root_paths the paths where to look for
+ /// seperate debug info.
+ ///
+ /// @param load_all_types if true, then load all the types described
+ /// in the binary, rather than loading only the types reachable from
+ /// the exported decls.
+ ///
+ /// @param linux_kernel_mode
+ void
+ initialize(const string& elf_path,
+ const vector<char**>& debug_info_root_paths,
+ bool load_all_types,
+ bool linux_kernel_mode)
+ {
+ reset(elf_path, debug_info_root_paths);
+ btf__free(btf_handle_);
+ options().load_all_types = load_all_types;
+ options().load_in_linux_kernel_mode = linux_kernel_mode;
+ }
+
+ /// Constructor of the btf::reader type.
+ ///
+ /// @param elf_path the path to the ELF file to analyze.
+ ///
+ /// @param debug_info_root_paths the set of directory where to look
+ /// debug info from, for cases where the debug is split.
+ ///
+ /// @param environment the environment of the current front-end.
+ ///
+ /// @param load_all_types if true load all the types described by
+ /// the BTF debug info, as opposed to loading only the types
+ /// reachable from the decls that are defined and exported.
+ ///
+ /// @param linux_kernel_mode if true, then consider the binary being
+ /// analyzed as a linux kernel binary.
+ reader(const string& elf_path,
+ const vector<char**>& debug_info_root_paths,
+ environment& environment,
+ bool load_all_types,
+ bool linux_kernel_mode)
+ : elf_based_reader(elf_path,
+ debug_info_root_paths,
+ environment)
+ {
+ initialize(elf_path, debug_info_root_paths,
+ load_all_types, linux_kernel_mode);
+ }
+
+public:
+
+ /// Constructor of the btf::reader type.
+ ///
+ /// @param elf_path the path to the ELF file to analyze.
+ ///
+ /// @param debug_info_root_paths the set of directory where to look
+ /// debug info from, for cases where the debug is split.
+ ///
+ /// @param environment the environment of the current front-end.
+ ///
+ /// @param load_all_types if true load all the types described by
+ /// the BTF debug info, as opposed to loading only the types
+ /// reachable from the decls that are defined and exported.
+ ///
+ /// @param linux_kernel_mode if true, then consider the binary being
+ /// analyzed as a linux kernel binary.
+ static btf::reader_sptr
+ create(const string& elf_path,
+ const vector<char**>& debug_info_root_paths,
+ environment& environment,
+ bool load_all_types,
+ bool linux_kernel_mode)
+ {
+ reader_sptr result(new reader(elf_path, debug_info_root_paths, environment,
+ load_all_types, linux_kernel_mode));
+ return result;
+ }
+
+ /// Destructor of the btf::reader type.
+ ~reader()
+ {
+ btf__free(btf_handle_);
+ }
+
+ /// Read the ELF information as well as the BTF type information to
+ /// build an ABI corpus.
+ ///
+ /// @param status output parameter. The status of the analysis.
+ ///
+ /// @return the resulting ABI corpus.
+ corpus_sptr
+ read_corpus(status& status)
+ {
+ // Read the properties of the ELF file.
+ elf::reader::read_corpus(status);
+
+ corpus::origin origin = corpus()->get_origin();
+ origin |= corpus::BTF_ORIGIN;
+ corpus()->set_origin(origin);
+
+ if ((status & STATUS_NO_SYMBOLS_FOUND)
+ || !(status & STATUS_OK))
+ // Either we couldn't find ELF symbols or something went badly
+ // wrong. There is nothing we can do with this ELF file. Bail
+ // out.
+ return corpus_sptr();
+
+ if (find_btf_section() == nullptr)
+ status |= STATUS_DEBUG_INFO_NOT_FOUND;
+
+ read_debug_info_into_corpus();
+
+ status |= STATUS_OK;
+
+ return corpus();
+ }
+
+ /// Read the BTF debug info to construct the ABI corpus.
+ ///
+ /// @return the resulting ABI corpus.
+ corpus_sptr
+ read_debug_info_into_corpus()
+ {
+ btf_handle();
+
+ translation_unit_sptr artificial_tu
+ (new translation_unit(env(), "", /*address_size=*/64));
+ corpus()->add(artificial_tu);
+ cur_tu(artificial_tu);
+
+ int number_of_types = nr_btf_types();
+ int first_type_id = 1;
+
+ // Let's cycle through whatever is described in the BTF section
+ // and emit libabigail IR for it.
+ for (int type_id = first_type_id;
+ type_id < number_of_types;
+ ++type_id)
+ {
+ // Build IR nodes only for decls (functions and variables)
+ // that have associated ELF symbols that are publicly defined
+ // and exported, unless the user asked to load all types.
+
+ bool do_construct_ir_node = false;
+
+ const btf_type* t = btf__type_by_id(btf_handle(), type_id);
+ string name;
+ if (t->name_off)
+ name = btf_offset_to_string(btf_handle(), t->name_off);
+
+ int kind = btf_kind(t);
+ if (kind == BTF_KIND_FUNC)
+ {
+ ABG_ASSERT(!name.empty());
+ if (btf_vlen(t) == BTF_FUNC_GLOBAL
+ || btf_vlen(t) == BTF_FUNC_EXTERN
+ || function_symbol_is_exported(name))
+ do_construct_ir_node = true;
+ }
+ else if (kind == BTF_KIND_VAR)
+ {
+ ABG_ASSERT(!name.empty());
+ if (btf_vlen(t) == BTF_VAR_GLOBAL_ALLOCATED
+ || btf_vlen(t) == BTF_VAR_GLOBAL_EXTERN
+ || variable_symbol_is_exported(name))
+ do_construct_ir_node = true;
+ }
+ else if (options().load_all_types)
+ do_construct_ir_node = true;
+
+ if (do_construct_ir_node)
+ build_ir_node_from_btf_type(type_id);
+ }
+
+ canonicalize_types();
+
+ return corpus();
+ }
+
+ /// Build an abigail IR node for a given type described by a BTF
+ /// type ID. The node is added to the ABI corpus.
+ ///
+ /// @param type_id the ID of the type to build and IR node for.
+ ///
+ /// @return the IR node representing the type @p type_id.
+ type_or_decl_base_sptr
+ build_ir_node_from_btf_type(int type_id)
+ {
+ type_or_decl_base_sptr result;
+ const btf_type *t = nullptr;
+
+ if ((result = lookup_artifact_from_btf_id(type_id)))
+ return result;
+
+ if (type_id == 0)
+ result = build_ir_node_for_void_type();
+ else
+ t = btf__type_by_id(btf_handle(), type_id);
+
+ if (!result)
+ {
+ ABG_ASSERT(t);
+ int type_kind = btf_kind(t);
+
+ switch(type_kind)
+ {
+ case BTF_KIND_INT/* Integer */:
+ result = build_int_type(type_id);
+ break;
+
+ case BTF_KIND_FLOAT/* Floating point */:
+ result = build_float_type(type_id);
+ break;
+
+ case BTF_KIND_TYPEDEF/* Typedef*/:
+ result = build_typedef_type(type_id);
+ break;
+
+ case BTF_KIND_PTR/* Pointer */:
+ result = build_pointer_type(type_id);
+ break;
+
+ case BTF_KIND_ARRAY/* Array */:
+ result = build_array_type(type_id);
+ break;
+
+ case BTF_KIND_ENUM/* Enumeration up to 32-bit values */:
+#ifdef WITH_BTF_ENUM64
+ case BTF_KIND_ENUM64/* Enumeration up to 64-bit values */:
+#endif
+ result = build_enum_type(type_id);
+ break;
+
+ case BTF_KIND_STRUCT/* Struct */:
+ case BTF_KIND_UNION/* Union */:
+ result = build_class_or_union_type(type_id);
+ break;
+
+ case BTF_KIND_FWD/* Forward */:
+ result = build_class_or_union_type(type_id);
+ break;
+
+ case BTF_KIND_CONST/* Const */:
+ case BTF_KIND_VOLATILE/* Volatile */:
+ case BTF_KIND_RESTRICT/* Restrict */:
+ result = build_qualified_type(type_id);
+ break;
+
+ case BTF_KIND_FUNC/* Function */:
+ result = build_function_decl(type_id);
+ break;
+
+ case BTF_KIND_FUNC_PROTO/* Function Proto */:
+ result = build_function_type(type_id);
+ break;
+
+ case BTF_KIND_VAR/* Variable */:
+ result = build_variable_decl(type_id);
+ break;
+
+#ifdef WITH_BTF_KIND_TYPE_TAG
+ case BTF_KIND_TYPE_TAG/* Type Tag */:
+#endif
+#ifdef WITH_BTF_KIND_DECL_TAG
+ case BTF_KIND_DECL_TAG/* Decl Tag */:
+#endif
+ case BTF_KIND_DATASEC/* Section */:
+ case BTF_KIND_UNKN/* Unknown */:
+ default:
+ ABG_ASSERT_NOT_REACHED;
+ break;
+ }
+ }
+
+ add_decl_to_scope(is_decl(result), cur_tu()->get_global_scope());
+
+ if (type_base_sptr type = is_type(result))
+ schedule_type_for_canonocalization(type);
+
+ associate_artifact_to_btf_type_id(result, type_id);
+
+ if (function_decl_sptr fn = is_function_decl(result))
+ {
+ if (fn->get_is_in_public_symbol_table())
+ maybe_add_fn_to_exported_decls(fn.get());
+ }
+ else if (var_decl_sptr var = is_var_decl(result))
+ {
+ if (var->get_is_in_public_symbol_table())
+ maybe_add_var_to_exported_decls(var.get());
+ }
+
+ return result;
+ }
+
+ /// Build an IR node for the "void" type.
+ ///
+ /// @return the IR node for the void type.
+ type_base_sptr
+ build_ir_node_for_void_type()
+ {
+ type_base_sptr t = env().get_void_type();
+ decl_base_sptr type_declaration = get_type_declaration(t);
+ if (!has_scope(type_declaration))
+ {
+ add_decl_to_scope(type_declaration, cur_tu()->get_global_scope());
+ canonicalize(t);
+ }
+
+ return t;
+ }
+
+ /// Build an IR node for the "variadic parameter" type.
+ ///
+ /// @return the IR node for the "variadic parameter" type.
+ type_base_sptr
+ build_ir_node_for_variadic_parameter_type()
+ {
+ type_base_sptr t = env().get_variadic_parameter_type();
+ decl_base_sptr t_decl = get_type_declaration(t);
+ if (!has_scope(t_decl))
+ {
+ add_decl_to_scope(t_decl, cur_tu()->get_global_scope());
+ canonicalize(t);
+ }
+ return t;
+ }
+
+ /// Build an IR node for an integer type expressed in BTF.
+ ///
+ /// @param t a pointer a BTF type describing an integer.
+ ///
+ /// @return a pointer to @ref type_decl representing an integer
+ /// type.
+ type_or_decl_base_sptr
+ build_int_type(int type_id)
+ {
+ type_decl_sptr result;
+
+ const btf_type *t = btf__type_by_id(btf_handle(), type_id);
+ ABG_ASSERT(btf_kind(t) == BTF_KIND_INT);
+
+ uint32_t info = *reinterpret_cast<const uint32_t*>(t + 1);
+ uint64_t byte_size = 0, bit_size = 0;
+ string type_name;
+
+ byte_size = t->size;
+ bit_size = byte_size * 8;
+
+ if (BTF_INT_ENCODING(info) & BTF_INT_CHAR)
+ {
+ if (!(BTF_INT_ENCODING(info) & BTF_INT_SIGNED))
+ type_name = "unsigned ";
+ type_name += "char";
+ }
+ else if (BTF_INT_ENCODING(info) & BTF_INT_BOOL)
+ type_name = "bool";
+ else if (!(BTF_INT_ENCODING(info) & BTF_INT_SIGNED))
+ {
+ type_name = "unsigned ";
+ type_name += btf_offset_to_string(btf_handle(), t->name_off);
+ }
+ else
+ type_name = btf_offset_to_string(btf_handle(), t->name_off);
+
+ location loc;
+ result.reset(new type_decl(env(), type_name,
+ bit_size, /*alignment=*/0,
+ loc, type_name));
+
+ return result;
+ }
+
+ /// Build an IR node for a float type expressed in BTF.
+ ///
+ /// @return a pointer to @ref type_decl representing a float type.
+ type_or_decl_base_sptr
+ build_float_type(int type_id)
+ {
+ const btf_type *t = btf__type_by_id(btf_handle(), type_id);
+ ABG_ASSERT(btf_kind(t) == BTF_KIND_FLOAT);
+
+ string type_name = btf_offset_to_string(btf_handle(), t->name_off);;
+ uint64_t byte_size = t->size, bit_size = byte_size * 8;
+ location loc;
+ type_decl_sptr result(new type_decl(env(), type_name, bit_size,
+ /*alignment=*/0, loc, type_name));
+
+ return result;
+ }
+
+ /// Build an IR type that represents the underlying type of an enum type.
+ ///
+ /// This is a sub-routine of the build_enum_type() function.
+ ///
+ /// @param enum_name the name of the enum type this type is an
+ /// underlying type for.
+ ///
+ /// @param enum_size the size of the enum.
+ ///
+ /// @param is_anonymous if true, the enum type is anonymous.
+ ///
+ /// @return a pointer to type_decl that represents a integer type
+ /// that is the underlying type of an enum type.
+ type_decl_sptr
+ build_enum_underlying_type(const string enum_name, uint64_t enum_size,
+ bool is_anonymous = true)
+ {
+ string underlying_type_name =
+ build_internal_underlying_enum_type_name(enum_name,
+ is_anonymous,
+ enum_size);
+ type_decl_sptr result(new type_decl(env(), underlying_type_name,
+ enum_size, enum_size, location()));
+ result->set_is_anonymous(is_anonymous);
+ result->set_is_artificial(true);
+ add_decl_to_scope(result, cur_tu()->get_global_scope());
+ canonicalize(result);
+ return result;
+ }
+
+ /// Build an IR node that represents an enum type expressed in BTF.
+ ///
+ /// @param type_id the ID of the BTF representation of the enum.
+ ///
+ /// @return a pointer to @ref enum_type_decl representing @p t.
+ type_or_decl_base_sptr
+ build_enum_type(int type_id)
+ {
+ const btf_type *t = btf__type_by_id(btf_handle(), type_id);
+ int kind = btf_kind(t);
+#ifdef WITH_BTF_ENUM64
+ ABG_ASSERT(kind == BTF_KIND_ENUM || kind == BTF_KIND_ENUM64);
+#else
+ ABG_ASSERT(kind == BTF_KIND_ENUM);
+#endif
+
+ int byte_size = t->size, bit_size = byte_size * 8;
+
+ string enum_name;
+ if (t->name_off)
+ enum_name = btf_offset_to_string(btf_handle(), t->name_off);
+ bool is_anonymous = enum_name.empty();
+
+ int num_enms = btf_vlen(t);
+ enum_type_decl::enumerators enms;
+ string e_name;
+ if (kind == BTF_KIND_ENUM)
+ {
+ const struct btf_enum* e = btf_enum(t);
+ uint32_t e_value = 0;
+ for (int i = 0; i < num_enms; ++i, ++e)
+ {
+ e_name = btf_offset_to_string(btf_handle(), e->name_off);
+ e_value = e->val;
+ enms.push_back(enum_type_decl::enumerator(e_name, e_value));
+ }
+ }
+#ifdef WITH_BTF_ENUM64
+ else if (kind == BTF_KIND_ENUM64)
+ {
+ const struct btf_enum64* e =
+ reinterpret_cast<const struct btf_enum64*>(t + 1);
+ uint64_t e_value = 0;
+ for (int i = 0; i < num_enms; ++i, ++e)
+ {
+ e_name = btf_offset_to_string(btf_handle(), e->name_off);
+ e_value = (static_cast<uint64_t>(e->val_hi32) << 32) | e->val_lo32;
+ enms.push_back(enum_type_decl::enumerator(e_name, e_value));
+ }
+ }
+#endif
+ else
+ ABG_ASSERT_NOT_REACHED;
+
+ type_decl_sptr underlying_type =
+ build_enum_underlying_type(enum_name, bit_size, is_anonymous);
+ enum_type_decl_sptr result(new enum_type_decl(enum_name,
+ location(),
+ underlying_type,
+ enms, enum_name));
+ result->set_is_anonymous(is_anonymous);
+ return result;
+ }
+
+ /// Build an IR node for a typedef that is expressed in BTF.
+ ///
+ /// @param type_id the ID of the BTF representation of a typedef.
+ ///
+ /// @return a pointer to @ref typedef_decl representing @p t.
+ type_or_decl_base_sptr
+ build_typedef_type(int type_id)
+ {
+ const btf_type *t = btf__type_by_id(btf_handle(), type_id);
+ int kind = btf_kind(t);
+ ABG_ASSERT(kind == BTF_KIND_TYPEDEF);
+
+ string type_name = btf_offset_to_string(btf_handle(), t->name_off);
+ type_base_sptr underlying_type =
+ is_type(build_ir_node_from_btf_type(t->type));
+ if (!underlying_type)
+ return type_or_decl_base_sptr();
+
+ typedef_decl_sptr result(new typedef_decl(type_name, underlying_type,
+ location(),
+ /*linkage_name=*/type_name));
+ if ((is_class_or_union_type(underlying_type)
+ || is_enum_type(underlying_type))
+ && is_anonymous_type(underlying_type))
+ get_type_declaration(underlying_type)->set_naming_typedef(result);
+
+ return result;
+ }
+
+ /// Build an IR node representing a pointer described in BTF.
+ ///
+ /// @param type_id the ID of a BTF representation of a pointer type.
+ ///
+ /// @return a pointer to pointer_type_def that represents @p t.
+ type_or_decl_base_sptr
+ build_pointer_type(int type_id)
+ {
+ const btf_type *t = btf__type_by_id(btf_handle(), type_id);
+ int kind = btf_kind(t);
+ ABG_ASSERT(kind == BTF_KIND_PTR);
+
+ type_base_sptr underlying_type =
+ is_type(build_ir_node_from_btf_type(t->type));
+ if (!underlying_type)
+ return type_or_decl_base_sptr();
+
+ int size = elf_helpers::get_architecture_word_size(elf_handle());
+ size *= 8;
+ pointer_type_def_sptr result(new pointer_type_def(underlying_type, size,
+ /*alignment=*/0,
+ location()));
+ return result;
+ }
+
+ /// Build an IR node representing an array type described in BTF.
+ ///
+ /// @param type_id the ID of the BTF representation of an array
+ /// type.
+ ///
+ /// return a pointer to @ref array_type_def representing @p t.
+ type_or_decl_base_sptr
+ build_array_type(int type_id)
+ {
+ const btf_type *t = btf__type_by_id(btf_handle(), type_id);
+ int kind = btf_kind(t);
+ ABG_ASSERT(kind == BTF_KIND_ARRAY);
+
+ const struct btf_array* arr = btf_array(t);
+
+ type_base_sptr underlying_type =
+ is_type(build_ir_node_from_btf_type(arr->type));
+ if (!underlying_type)
+ return type_or_decl_base_sptr();
+
+ uint64_t lower_boud = 0;
+ // Note that arr->nelems can be 0;
+ uint64_t upper_bound = arr->nelems ? arr->nelems - 1: 0;
+
+ array_type_def::subrange_sptr subrange(new array_type_def::subrange_type
+ (env(), /*name=*/"",
+ lower_boud, upper_bound,
+ location()));
+ add_decl_to_scope(subrange, cur_tu()->get_global_scope());
+ canonicalize(subrange);
+ array_type_def::subranges_type subranges = {subrange};
+ array_type_def_sptr result(new array_type_def(underlying_type,
+ subranges, location()));
+
+ return result;
+ }
+
+ /// Build an IR node representing a qualified type described in BTF.
+ ///
+ /// @param type_id the ID of the BTF representation of an array
+ /// type.
+ ///
+ /// @return a pointer to a qualified_type_def representing @ t.
+ type_or_decl_base_sptr
+ build_qualified_type(int type_id)
+ {
+ const btf_type *t = btf__type_by_id(btf_handle(), type_id);
+ int kind = btf_kind(t);
+ ABG_ASSERT(kind == BTF_KIND_CONST
+ || kind == BTF_KIND_VOLATILE
+ || kind == BTF_KIND_RESTRICT);
+
+ type_base_sptr underlying_type =
+ is_type(build_ir_node_from_btf_type(t->type));
+ if (!underlying_type)
+ return type_or_decl_base_sptr();
+
+ qualified_type_def::CV qual = qualified_type_def::CV_NONE;
+ if (kind == BTF_KIND_CONST)
+ qual |= qualified_type_def::CV_CONST;
+ else if (kind == BTF_KIND_VOLATILE)
+ qual |= qualified_type_def::CV_VOLATILE;
+ else if (kind == BTF_KIND_RESTRICT)
+ qual |= qualified_type_def::CV_RESTRICT;
+ else
+ ABG_ASSERT_NOT_REACHED;
+
+ qualified_type_def_sptr result(new qualified_type_def(underlying_type,
+ qual, location()));
+ return result;
+ }
+
+ /// Build an IR node for a class or union type expressed in BTF.
+ ///
+ /// @param type_id the ID of a pointer to a BTF type describing a
+ /// class or union type.
+ ///
+ /// @return a pointer to either a @ref class_decl or a @ref
+ /// union_decl type representing the type expressed by @p t.
+ type_or_decl_base_sptr
+ build_class_or_union_type(int type_id)
+ {
+ const btf_type *t = btf__type_by_id(btf_handle(), type_id);
+
+ int kind = btf_kind(t);
+ ABG_ASSERT(kind == BTF_KIND_STRUCT
+ || kind == BTF_KIND_UNION
+ || kind == BTF_KIND_FWD);
+
+ string type_name;
+ if (t->name_off)
+ type_name = btf_offset_to_string(btf_handle(), t->name_off);
+
+ bool is_anonymous = type_name.empty();
+ uint64_t size = t->size;
+ size *= 8;
+
+ bool is_decl_only = (kind == BTF_KIND_FWD);
+
+ class_or_union_sptr result;
+ if (kind == BTF_KIND_STRUCT
+ || (kind == BTF_KIND_FWD
+ && BTF_INFO_KFLAG(t->info) == 0 /*struct*/))
+ result.reset(new class_decl(env(), type_name, size,
+ /*alignment=*/0,
+ /*is_struct=*/true,
+ location(),
+ decl_base::VISIBILITY_DEFAULT,
+ is_anonymous));
+ else if (kind == BTF_KIND_UNION
+ || (kind == BTF_KIND_FWD
+ && BTF_INFO_KFLAG(t->info) == 1/*union*/))
+ result.reset(new union_decl(env(), type_name, size, location(),
+ decl_base::VISIBILITY_DEFAULT,
+ is_anonymous));
+ else
+ ABG_ASSERT_NOT_REACHED;
+
+ if (is_decl_only)
+ result->set_is_declaration_only(is_decl_only);
+
+ add_decl_to_scope(result, cur_tu()->get_global_scope());
+
+ associate_artifact_to_btf_type_id(result, type_id);
+
+ // For defined classes and unions, add data members to the type
+ // being built.
+ if (!is_decl_only)
+ {
+ const struct btf_member *m =
+ reinterpret_cast<const struct btf_member*>(t + 1);
+ uint64_t nb_members = btf_vlen(t);
+
+ for (uint64_t i = 0; i < nb_members; ++i, ++m)
+ {
+ type_base_sptr member_type =
+ is_type(build_ir_node_from_btf_type(m->type));
+ if (!member_type)
+ continue;
+
+ string member_name;
+ if (m->name_off)
+ member_name = btf_offset_to_string(btf_handle(), m->name_off);
+ var_decl_sptr data_member(new var_decl(member_name,
+ member_type,
+ location(),
+ /*linkage_name=*/""));
+ uint64_t offset_in_bits =
+ BTF_INFO_KFLAG(t->info)
+ ? BTF_MEMBER_BIT_OFFSET(m->offset)
+ : m->offset;
+
+ result->add_data_member(data_member,
+ public_access,
+ /*is_laid_out=*/true,
+ /*is_static=*/false,
+ offset_in_bits);
+ }
+ }
+ return result;
+ }
+
+ /// Build an IR node for a function type expressed in BTF.
+ ///
+ /// @param type_id the ID of a pointer to a BTF type describing a
+ /// function type.
+ ///
+ /// @return a pointer to a @ref function_type representing the
+ /// function type expressed by @p t.
+ type_or_decl_base_sptr
+ build_function_type(int type_id)
+ {
+ const btf_type *t = btf__type_by_id(btf_handle(), type_id);
+ int kind = btf_kind(t);
+ ABG_ASSERT(kind == BTF_KIND_FUNC_PROTO);
+
+ type_base_sptr return_type = is_type(build_ir_node_from_btf_type(t->type));
+ if (return_type == nullptr)
+ return type_or_decl_base_sptr();
+
+ int address_size = elf_helpers::get_architecture_word_size(elf_handle());
+ address_size *= 8;
+ function_type_sptr result(new function_type(env(), address_size,
+ /*alignment=*/0));
+ result->set_return_type(return_type);
+
+ associate_artifact_to_btf_type_id(result, type_id);
+
+ uint16_t nb_parms = btf_vlen(t);
+ const struct btf_param* parm =
+ reinterpret_cast<const struct btf_param*>(t + 1);
+
+ function_decl::parameters function_parms;
+ for (uint16_t i = 0; i < nb_parms; ++i, ++parm)
+ {
+ type_base_sptr parm_type;
+ string parm_name;
+ bool is_variadic = false;
+
+ if (parm->name_off == 0 && parm->type == 0)
+ {
+ is_variadic = true;
+ parm_type = build_ir_node_for_variadic_parameter_type();
+ }
+ else
+ {
+ parm_name = btf_offset_to_string(btf_handle(), parm->name_off);
+ parm_type = is_type(build_ir_node_from_btf_type(parm->type));
+ }
+
+ if (!parm_type)
+ continue;
+
+ function_decl::parameter_sptr p
+ (new function_decl::parameter(parm_type, parm_name,
+ location(), is_variadic));
+ function_parms.push_back(p);
+ }
+ result->set_parameters(function_parms);
+
+ cur_tu()->bind_function_type_life_time(result);
+
+ return result;
+ }
+
+ /// Build an IR node for a function declaration expressed in BTF.
+ ///
+ /// @param type_id the ID of a pointer to a BTF "type" which realy
+ /// describes a function declaration.
+ ///
+ /// @return a pointer to a @ref function_decl representing the
+ /// function declaration expressed by @p t.
+ type_or_decl_base_sptr
+ build_function_decl(int type_id)
+ {
+ const btf_type *t = btf__type_by_id(btf_handle(), type_id);
+ int kind = btf_kind(t);
+ ABG_ASSERT(kind == BTF_KIND_FUNC);
+
+ function_decl_sptr result;
+
+ string fn_name = btf_offset_to_string(btf_handle(), t->name_off);
+
+ type_base_sptr fn_type = is_type(build_ir_node_from_btf_type(t->type));
+ if (!fn_type)
+ return result;
+
+ result.reset(new function_decl(fn_name, fn_type, /*is_inline=*/false,
+ location(), /*linkage_name=*/fn_name));
+
+ elf_symbol_sptr fn_sym;
+ if ((fn_sym = function_symbol_is_exported(fn_name)))
+ {
+ result->set_symbol(fn_sym);
+ result->set_is_in_public_symbol_table(true);
+ }
+ return result;
+ }
+
+ /// Build an IR node for a variable declaration expressed in BTF.
+ ///
+ /// @param t a pointer to a BTF "type" describing a variable
+ /// declaration.
+ ///
+ /// @return a pointer to @ref var_decl representing the variable
+ /// declaration expressed by @p t.
+ type_or_decl_base_sptr
+ build_variable_decl(int type_id)
+ {
+ const btf_type *t = btf__type_by_id(btf_handle(), type_id);
+ int kind = btf_kind(t);
+ ABG_ASSERT(kind == BTF_KIND_VAR);
+
+ var_decl_sptr result;
+
+ string var_name = btf_offset_to_string(btf_handle(), t->name_off);
+
+ type_base_sptr var_type = is_type(build_ir_node_from_btf_type(t->type));
+ if (!var_type)
+ return result;
+
+ result.reset(new var_decl(var_name, var_type, location(),
+ /*linkage_name=*/var_name));
+
+ elf_symbol_sptr var_sym;
+ if ((var_sym = variable_symbol_is_exported(var_name)))
+ {
+ result->set_symbol(var_sym);
+ result->set_is_in_public_symbol_table(true);
+ }
+ return result;
+ }
+
+}; // end class reader.
+
+/// Create and return a BTF reader (or front-end) which is an instance
+/// of @ref btf::reader.
+///
+/// @param elf_path the path to the path to the elf file the reader is
+/// to be used for.
+///
+/// @param debug_info_root_paths a vector to the paths to the
+/// directories under which the debug info is to be found for @p
+/// elf_path. Pass an empty vector if th debug info is not in a split
+/// file.
+///
+/// @param environment the environment used by the current context.
+/// This environment contains resources needed by the BTF reader and
+/// by the types and declarations that are to be created later. Note
+/// that ABI artifacts that are to be compared all need to be created
+/// within the same environment.
+///
+/// Please also note that the life time of this environment object
+/// must be greater than the life time of the resulting @ref
+/// reader the context uses resources that are allocated in the
+/// environment.
+///
+/// @param load_all_types if set to false only the types that are
+/// reachable from publicly exported declarations (of functions and
+/// variables) are read. If set to true then all types found in the
+/// debug information are loaded.
+///
+/// @param linux_kernel_mode if set to true, then consider the special
+/// linux kernel symbol tables when determining if a symbol is
+/// exported or not.
+///
+/// @return a smart pointer to the resulting btf::reader.
+elf_based_reader_sptr
+create_reader(const std::string& elf_path,
+ const vector<char**>& debug_info_root_paths,
+ environment& env,
+ bool load_all_types,
+ bool linux_kernel_mode)
+{
+ reader_sptr rdr = reader::create(elf_path, debug_info_root_paths, env,
+ load_all_types, linux_kernel_mode);
+ return rdr;
+}
+
+} // end namespace btf
+} // end namespace abigail
+
+#endif //WITH_BTF
@@ -274,6 +274,7 @@ struct reader::priv
int alt_ctf_fd = 0;
Elf* alt_ctf_handle = nullptr;
Elf_Scn* alt_ctf_section = nullptr;
+ Elf_Scn* btf_section = nullptr;
priv(reader& reeder, const std::string& elf_path,
const vector<char**>& debug_info_roots)
@@ -602,6 +603,13 @@ bool
reader::has_ctf_debug_info() const
{return (priv_->ctf_section != nullptr);}
+/// Test if the binary has BTF debug info.
+///
+/// @return true iff the binary has BTF debug info
+bool
+reader::has_btf_debug_info() const
+{return (priv_->btf_section != nullptr);}
+
/// Getter of the handle use to access DWARF information from the
/// alternate split DWARF information.
///
@@ -697,6 +705,20 @@ reader::find_alternate_ctf_section() const
return priv_->alt_ctf_section;
}
+/// Find and return a pointer to the BTF section of the current ELF
+/// file.
+///
+/// @return a pointer to the BTF section of the current ELF file.
+const Elf_Scn*
+reader::find_btf_section() const
+{
+ if (priv_->btf_section == nullptr)
+ priv_->btf_section =
+ elf_helpers::find_section(priv_->elf_handle,
+ ".BTF", SHT_PROGBITS);
+ return priv_->btf_section;
+}
+
/// Get the value of the DT_NEEDED property of the current ELF file.
///
/// @return the value of the DT_NEEDED property.
@@ -47,6 +47,9 @@
#ifdef WITH_CTF
#include "abg-ctf-reader.h"
#endif
+#ifdef WITH_BTF
+#include "abg-btf-reader.h"
+#endif
#include "abg-internal.h"
#include "abg-regex.h"
@@ -504,6 +507,34 @@ file_has_ctf_debug_info(const string& elf_file_path,
return false;
}
+/// Test if an ELF file has BTFG debug info.
+///
+/// @param elf_file_path the path to the ELF file to consider.
+///
+/// @param debug_info_root a vector of pointer to directory to look
+/// for debug info, in case the file is associated to split debug
+/// info. If there is no split debug info then this vector can be
+/// empty. Note that convert_char_stars_to_char_star_stars() can be
+/// used to ease the construction of this vector.
+///
+/// @return true iff the ELF file at @elf_file_path is an ELF file
+/// that contains debug info.
+bool
+file_has_btf_debug_info(const string& elf_file_path,
+ const vector<char**>& debug_info_root_paths)
+{
+ if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
+ return false;
+
+ environment env;
+ elf::reader r(elf_file_path, debug_info_root_paths, env);
+
+ if (r.find_btf_section())
+ return true;
+
+ return false;
+}
+
/// Tests if a given path is a directory or a symbolic link to a
/// directory.
///
@@ -2850,6 +2881,13 @@ create_best_elf_based_reader(const string& elf_file_path,
#ifdef WITH_CTF
if (file_has_ctf_debug_info(elf_file_path, debug_info_root_paths))
result = ctf::create_reader(elf_file_path, debug_info_root_paths, env);
+#endif
+ }
+ else if (requested_fe_kind & corpus::BTF_ORIGIN)
+ {
+#ifdef WITH_BTF
+ if (file_has_btf_debug_info(elf_file_path, debug_info_root_paths))
+ result = btf::create_reader(elf_file_path, debug_info_root_paths, env);
#endif
}
else
@@ -2862,6 +2900,14 @@ create_best_elf_based_reader(const string& elf_file_path,
// front end even if it wasn't formally requested by the user.
result = ctf::create_reader(elf_file_path, debug_info_root_paths, env);
#endif
+
+#ifdef WITH_BTF
+ if (!file_has_dwarf_debug_info(elf_file_path, debug_info_root_paths)
+ && file_has_btf_debug_info(elf_file_path, debug_info_root_paths))
+ // The file has BTF debug info and no BTF, let's use the BTF
+ // front-end even if it wasn't formally requested by the user.
+ result = btf::create_reader(elf_file_path, debug_info_root_paths, env);
+#endif
}
if (!result)
@@ -30,6 +30,10 @@ if CTF_READER
TESTS += runtestreadctf
endif
+if BTF_READER
+TESTS += runtestreadbtf
+endif
+
# rather cheap tests
TESTS+= \
runtestabicompat \
@@ -111,6 +115,13 @@ runtestreadctf_LDADD=libtestreadcommon.la libtestutils.la \
runtestreadctf_LDFLAGS=-pthread
endif
+if BTF_READER
+runtestreadbtf_SOURCES=test-read-btf.cc
+runtestreadbtf_LDADD=libtestreadcommon.la libtestutils.la \
+ $(top_builddir)/src/libabigail.la
+runtestreadbtf_LDFLAGS=-pthread
+endif
+
runtestannotate_SOURCES=test-annotate.cc
runtestannotate_LDADD=libtestutils.la $(top_builddir)/src/libabigail.la
@@ -242,6 +242,12 @@ test-abidiff-exit/test-rhbz2114909-v0.o \
test-abidiff-exit/test-rhbz2114909-v1.cc \
test-abidiff-exit/test-rhbz2114909-v1.o \
test-abidiff-exit/test-rhbz2114909-report-1.txt \
+test-abidiff-exit/btf/test0-report-1.txt \
+test-abidiff-exit/btf/test0-report-2.txt \
+test-abidiff-exit/btf/test0-v0.c \
+test-abidiff-exit/btf/test0-v0.o \
+test-abidiff-exit/btf/test0-v1.c \
+test-abidiff-exit/btf/test0-v1.o \
\
test-diff-dwarf/test0-v0.cc \
test-diff-dwarf/test0-v0.o \
@@ -721,6 +727,13 @@ test-read-ctf/test-array-size.abi \
test-read-ctf/test-array-size.c \
test-read-ctf/test-array-size.o \
\
+test-read-btf/test0.c \
+test-read-btf/test0.o \
+test-read-btf/test0.o.abi \
+test-read-btf/test1.c \
+test-read-btf/test1.o \
+test-read-btf/test1.o.abi \
+\
test-annotate/test0.abi \
test-annotate/test1.abi \
test-annotate/test2.so.abi \
new file mode 100644
@@ -0,0 +1,16 @@
+Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added variable
+
+1 function with some indirect sub-type change:
+
+ [C] 'function void fn0(const foo_type*)' has some indirect sub-type changes:
+ return type changed:
+ type name changed from 'void' to 'int'
+ type size changed from 0 to 32 (in bits)
+ mangled name changed from '' to int
+ parameter 1 of type 'const foo_type*' changed:
+ in pointed to type 'const foo_type':
+ entity changed from 'const foo_type' to 'typedef foo_type'
+ type size hasn't changed
+ parameter 2 of type 'int' was added
+
new file mode 100644
@@ -0,0 +1,53 @@
+Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+Variables changes summary: 0 Removed, 1 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+ [C] 'function void fn0(const foo_type*)' has some indirect sub-type changes:
+ return type changed:
+ type name changed from 'void' to 'int'
+ type size changed from 0 to 32 (in bits)
+ mangled name changed from '' to int
+ parameter 1 of type 'const foo_type*' changed:
+ in pointed to type 'const foo_type':
+ entity changed from 'const foo_type' to 'typedef foo_type'
+ type size hasn't changed
+ parameter 2 of type 'int' was added
+
+1 Changed variable:
+
+ [C] 'foo_type foos[2]' was changed:
+ type of variable changed:
+ array element type 'struct foo_type' changed:
+ type size hasn't changed
+ 2 data member changes:
+ type of 'const int* m0' changed:
+ in pointed to type 'const int':
+ entity changed from 'const int' to 'int'
+ type size hasn't changed
+ type of 'volatile const u_type* m5' changed:
+ in pointed to type 'volatile const u_type':
+ in unqualified underlying type 'typedef u_type':
+ underlying type 'union u_type' changed:
+ type size hasn't changed
+ 1 data member insertion:
+ 'char* m2'
+ 2 data member changes:
+ type of 'ENUM_TYPE* m0' changed:
+ in pointed to type 'typedef ENUM_TYPE':
+ underlying type 'enum ENUM_TYPE' changed:
+ type size hasn't changed
+ 1 enumerator insertion:
+ 'ENUM_TYPE::E2_ENUM_TYPE' value '2'
+ type of 'ANOTHER_ENUM_TYPE* m1' changed:
+ in pointed to type 'typedef ANOTHER_ENUM_TYPE':
+ underlying type 'enum ANOTHER_ENUM_TYPE' changed:
+ type size hasn't changed
+ 1 enumerator insertion:
+ 'ANOTHER_ENUM_TYPE::E2_ANOTHER_ENUM_TYPE' value '2'
+ type changed from:
+ union u_type{ENUM_TYPE* m0; ANOTHER_ENUM_TYPE* m1;}
+ to:
+ union u_type{ENUM_TYPE* m0; ANOTHER_ENUM_TYPE* m1; char* m2;}
+ type size hasn't changed
+
new file mode 100644
@@ -0,0 +1,40 @@
+/*
+ * Compile this to emit BTF debug info with:
+ *
+ * gcc -c -gbtf test0.c
+ */
+
+typedef enum ENUM_TYPE
+{
+ E0_ENUM_TYPE = 0,
+ E1_ENUM_TYPE= 1
+} ENUM_TYPE;
+
+typedef enum ANOTHER_ENUM_TYPE
+{
+ E0_ANOTHER_ENUM_TYPE = 0,
+ E1_ANOTHER_ENUM_TYPE= 1
+} ANOTHER_ENUM_TYPE;
+
+typedef union u_type
+{
+ ENUM_TYPE *m0;
+ ANOTHER_ENUM_TYPE *m1;
+} u_type;
+
+typedef struct foo_type
+{
+ const int *m0;
+ volatile char *m1;
+ unsigned *m2;
+ const volatile unsigned char *m3;
+ float m4[10];
+ volatile const u_type *m5;
+} foo_type;
+
+void
+fn0(const foo_type* p __attribute__((unused)))
+{
+}
+
+struct foo_type foos[2] = {0};
new file mode 100644
GIT binary patch
literal 2320
zcmbtVOK%)S5U!ax&f3_<3Gal*<bX&dJo^Zdf`!lqYn|m~EXzJ{i0s+j*$3?GtairH
z8VQjTQaA+(i5uj`0f`F|0#1=QAaTlXK#GLKDK{hz@O{(Wp3bm0N?To3UsZMYR9E+Y
z(s*anbsRC|$m^0@1{Jw?GS};wT9;*6lD+1w`^{S)|8@KNFL{8aef_5+PiwpHijdc_
z0M~#zKL`1U_A`$7i^_KB^T0J_m*{&9Z1T1gE^SEqrphic?=vvsPL?1)2cH6yz5o-m
z$UTu8E<f{2WtZl2d~qSy7Z#y^1%`ia8}eK5qhQka;4|Pl_y_P~;G5uI!B2tjf`12}
z1#{E)A<lv8*z7mNfa>q&Cy^GHmE`EIVE9hi*{R`M%=Q;n70%H;ZRwa=ep0r{Aw*hy
zTuF`#PvpA$B=p~uy~_REQ@X?2)s@aMTbt+h448G%<nm1aP)2FVpa^+3*Rx#um}@qK
zkIp{#5)?0wb)SR&K-nwLL$Wx3D|_h$$jbom%Z}l^!sQNSV{7l-{oVJs8`7xkTSnC~
z4oAtLHwru6V3b-3SGV5VZ8mnSKuj?Mtj+-c8+N##9*skZDiT#i8{IfoC>MsO-47;o
zM>RR#lfo`ZcNhn$4C7JHJN9L1uSj%Rj%R|B$c=c=k?yD><$fH6<xbrBU{LN2((-W7
z3R;6+Fc_9wX}26sgJ?VqlX4m+X=Uw3#czv@#cw5v$hD1)b??Hpt-Xt0wdU9Ss#mMj
zYLzS1SG@~6C{{B_wPUSzQI}kF?+Wh`QgN=%U1EkDZS(v{rvIFecEp*kI_H*7m2Shy
zJ~6$Ly$@GcRzGz&mghGSkY&yuIPaW1_-B^)MAkJAd)R+xEZn?Byi2E#ua>A@Vyaas
z7C0+6V2?f!``Gky2KdQQlm;#FlXRkF-)Lz#O~vm7X`m|Zzp=Y1emjn$5bfZP;xzP8
z!?h$0+8=7WH#+pklXx6X(j)OF;V|&S{(g57L}9kv{~h=iv4+;$mrYsE#{8|;rd2tG
zoQGh(d6Z1t+eRr!#@h4}44!W>|3C-b(b5RdC|bS@S)7xu0}h~{3lkS(tB4_1VX#GK
zbrY8@jH<~ua^1r0&^PT%U^z^lf!>0`|Eh<22==zlFYc>&7g~troW=Z`I{ylMHWl-)
z!^zOP9R$6}3k~91PvTq8T$69`S!*-?N4@@(28j2JM^Vh@|7_uifZ#mz`qqC`h8OF{
R|GioH2ReV4W#vOL|6h!W&5-~A
literal 0
HcmV?d00001
@@ -0,0 +1,45 @@
+/*
+ * Compile this to emit BTF debug info with:
+ *
+ * gcc -c -gbtf test0.c
+ */
+
+typedef enum ENUM_TYPE
+{
+ E0_ENUM_TYPE = 0,
+ E1_ENUM_TYPE= 1,
+ E2_ENUM_TYPE= 2
+} ENUM_TYPE;
+
+typedef enum ANOTHER_ENUM_TYPE
+{
+ E0_ANOTHER_ENUM_TYPE = 0,
+ E1_ANOTHER_ENUM_TYPE= 1,
+ E2_ANOTHER_ENUM_TYPE= 2
+} ANOTHER_ENUM_TYPE;
+
+typedef union u_type
+{
+ ENUM_TYPE *m0;
+ ANOTHER_ENUM_TYPE *m1;
+ char *m2;
+} u_type;
+
+typedef struct foo_type
+{
+ int *m0;
+ volatile char *m1;
+ unsigned *m2;
+ const volatile unsigned char *m3;
+ float m4[10];
+ volatile const u_type *m5;
+} foo_type;
+
+int
+fn0(foo_type* p, int a)
+{
+ *p->m0 = a;
+ return a;
+}
+
+struct foo_type foos[2] = {0};
new file mode 100644
GIT binary patch
literal 2376
zcmbtVOK%%h6h1Re6DP#MEl?ieF)R?RM8@_2Qt1L*BDV&WP=#0(YO8ddj340fSe^+=
zkPwj&h$tJDhz<P#?2r&_P!SupEGi)(v10`itrVp0==aUs8{ba7<H+AVukYMDbM77A
zkLwrC*_I_*EO}MNo{owXrpI<IHEU9od1*HG{%q`hbZ2ktps`=S)7Y2&=D}WRzkYD_
zXVSj@%aX@ZzR0ef;R+Vu8b?H?r=TBDdGZ*44ggg=0Ai8j0Iva%0y%F0y8bewkRia_
zrvU4}0w4v}e*=Jjv;h4rFauD&0~n+H2+XC{;b5aii+vQ<51E&C40Sqf&uW&)EbX5%
z-)!65yum5L{sll=r!GR@1daie-+<#l4fq{+2-pSw1|9`&05f>eC!qPlbHF0Z8eaNW
z#>PEECKbD+3@BUon>PFON0!s?#1Lif;Y@R!ePnFgCt&}R`6c%D-^{ky$697{OnbvU
zeH<|QYA?VqW=~dl5Vn$(PoI4K5YR<F`#a!21Kor+-{ncfPGoZ}JO!KPV&>034f_&o
z{L*C{_>}7$>MPB+*4N&>SeJTb-EgX=;~CD@AntVr!KTw2Bu4ewmABU#^;Lt2`6dLb
zlY-ua;Qh5*>&ebAkgy_QRW`c*NJ39kupLENmQR&2nAFdjv0s#SKk^glM}v-Ym`f{O
zlJI3YoCHQJ?LkG#-6#yoo6+Wby>h3Ql>5Dw-|BVzUccN*+T~!|4~P9AE+;{pRF*!d
zx*Pobd~sWGEOLH%`HXY&{7UnbQ}tZWtvX)C^D3vSuQ(@H(ZPnFsKk<YikpFt0B`_)
zV<^P_TQ?ZfVktk{S`mFVtq)hl+Adj(^D~7nkmPwFD5*ZXQ2NYXE>2$pAq!6&Iq#I*
z{%=z9NP4R7&G1`3Zp8JPJe$W3{}$9)W2w<8HaP7x!VYr~o_Brb(|{ZAgo)o0H%>;G
z?rJLuwi9tT{Y3TKeSPhmxEoOz1~>%nAW8xkJzR<tf8%}ScLrPTa1;%LQL-cMDCqlc
z&|Pnj{4hwD`@aMKf7nCgnn<UtrQ>){lxuV@i#!X(di{s0c~`WN)8v}+JRI(CzW$mb
zT~}HwM;l7N0G*$cscRe{2f2y!+$uPXRY*2uO&#L05u>T=wLW9SOzJ1*M_?p$oesST
zgLm3JX9)i1sy_c*`EQ{GF6YeGf3NCKBWFs!{wk8B)=U!YU4GCI-UAfg1FY5cIzDM_
v@^7j2x9LE5cX2E7^}KU)TZD*6SFLZ{UuitwKi<8Q>c3R={j_R4<m>MO6Qkh~
literal 0
HcmV?d00001
@@ -0,0 +1,40 @@
+/*
+ * Compile this to emit BTF debug info with:
+ *
+ * gcc -c -gbtf test0.c
+ */
+
+typedef enum ENUM_TYPE
+{
+ E0_ENUM_TYPE = 0,
+ E1_ENUM_TYPE= 1
+} ENUM_TYPE;
+
+typedef enum ANOTHER_ENUM_TYPE
+{
+ E0_ANOTHER_ENUM_TYPE = 0,
+ E1_ANOTHER_ENUM_TYPE= 1
+} ANOTHER_ENUM_TYPE;
+
+typedef union u_type
+{
+ ENUM_TYPE *m0;
+ ANOTHER_ENUM_TYPE *m1;
+} u_type;
+
+typedef struct foo_type
+{
+ const int *m0;
+ volatile char *m1;
+ unsigned *m2;
+ const volatile unsigned char *m3;
+ float m4[10];
+ volatile const u_type *m5;
+} foo_type;
+
+void
+fn0(const foo_type* p __attribute__((unused)))
+{
+}
+
+struct foo_type foos[2] = {0};
new file mode 100644
GIT binary patch
literal 2312
zcmbtV&5ImG6o1{>Y-ZQpbrV0L#*fZH+<@tsX%%A-nYhemFuI0i7xWM|Ju^KYIz2s1
z_sXmwdJ^I(g5XVa^B{;IDBc1d6i@yQLO}48o8Uozzpkq7N;@|n^Xk3#d+$|Mzj{^k
zVe|DZ*Kx#<Bd<td8C2w#<AvVH)rPFfitM#++-cqT;IEt4ekuYi?aMzMc|_X-SA_f`
z7T_9C7Z)J!(|*Pge_GiNeI7Vac7?u|!6t88;nIPmZ>H=D^F9G1?sx_AQ}78e=`%1f
zi`-*{;qo&-S9WEwz?YW_eQ6o`7hw1ou0nndz8_5b4txsS0DljD0Q?d7XYgt8ZSe2l
z$H3h59f&jF1~&T@F`)Xp`AMYZRV6vPYZ$&!c7AI37PI}Ob%k?uPg**rmLHXEatM)@
zA5@a#(nE#rJ`DX=Wv_ETzbV~e?HWqwn6J%qdlbyNXmWX`e<-7}Vo-!UUg&u)eatl*
z!bj(yTZ7^ivF;Pl?<#xkNk|swZ)LAM1sMRqFF%H}3YS}y&F#H6_IKaD+LUH(-!kf!
zaWGDY{c+UwhU3gixU~J|ZmYRt1!9UhV0{kw->`%I>~IoET$8vi+UO;TLb)(Jok2LI
zI}YS%PYQcZdZQ%FWR#5i-jOd)dtTxf<Y*=+sl1mAyV4uiq&i6AsM<}s?+mN`VOAXt
z+hKdy4~L^_JL^@WSr|`7QCiKSG^_a?k%{>2G!?nLxp~psxV*i0&Z`H0;McvN76i2m
z^_RSj9aO3nX4-K+IEOOpo)z97WZ^uW+r$hx+UB{DOy4>0?}#&7ch0PwsN95;{b70}
ze-|#Tt$*xpt}bpNAkUmXaNY&E`_DY@vAkRE_3%EQvT*YTvH4COT`5sL#8guuRyD6N
zK@l$>RsWhE&LKZNjI*#Uews~{92hN&W|{ciFbh?&{a1Il#P1|=9H9;Tags$oYIr`)
z!p^(e?vD@r$uyZn)9g_EX*3G`Xt3X#hH<2K@c#tgAlA@&^YRHB`B=Qs+O#UCkh2iX
zH;<8tyJD1*WUNikz~K3o^RMfmTUr|78AZ!yA<J{pb)5s~htkC5*g9f})fjBiY2CzC
z3!`fCjl5`KcIcLU2`q=nGtg^L_#bso55aEf{PMoaccG0~&RNc%>HG`u*;LNI1}8%s
zb`Wh|Xb|6c65n{{ntX%LTbuFU>h)(dK)h!>igG^hW9f*1h-~Qf`JZZ2xqke=o0tEV
M&L7#y(98M%0waFQm;e9(
literal 0
HcmV?d00001
@@ -0,0 +1,90 @@
+<abi-corpus version='2.1' path='data/test-read-btf/test0.o'>
+ <elf-function-symbols>
+ <elf-symbol name='fn0' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ </elf-function-symbols>
+ <elf-variable-symbols>
+ <elf-symbol name='foos' size='160' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ </elf-variable-symbols>
+ <abi-instr address-size='64'>
+ <type-decl name='char' size-in-bits='8' id='type-id-1'/>
+ <enum-decl name='ANOTHER_ENUM_TYPE' linkage-name='ANOTHER_ENUM_TYPE' id='type-id-2'>
+ <underlying-type type-id='type-id-3'/>
+ <enumerator name='E0_ANOTHER_ENUM_TYPE' value='0'/>
+ <enumerator name='E1_ANOTHER_ENUM_TYPE' value='1'/>
+ </enum-decl>
+ <enum-decl name='ENUM_TYPE' linkage-name='ENUM_TYPE' id='type-id-4'>
+ <underlying-type type-id='type-id-5'/>
+ <enumerator name='E0_ENUM_TYPE' value='0'/>
+ <enumerator name='E1_ENUM_TYPE' value='1'/>
+ </enum-decl>
+ <type-decl name='enum-ANOTHER_ENUM_TYPE-underlying-type-32' size-in-bits='32' alignment-in-bits='32' id='type-id-3'/>
+ <type-decl name='enum-ENUM_TYPE-underlying-type-32' size-in-bits='32' alignment-in-bits='32' id='type-id-5'/>
+ <type-decl name='float' size-in-bits='32' id='type-id-6'/>
+ <array-type-def dimensions='1' type-id='type-id-6' size-in-bits='320' id='type-id-7'>
+ <subrange length='10' id='type-id-8'/>
+ </array-type-def>
+ <array-type-def dimensions='1' type-id='type-id-9' size-in-bits='1280' id='type-id-10'>
+ <subrange length='2' id='type-id-11'/>
+ </array-type-def>
+ <type-decl name='int' size-in-bits='32' id='type-id-12'/>
+ <class-decl name='foo_type' size-in-bits='640' is-struct='yes' visibility='default' id='type-id-9'>
+ <data-member access='public' layout-offset-in-bits='0'>
+ <var-decl name='m0' type-id='type-id-13' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='64'>
+ <var-decl name='m1' type-id='type-id-14' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='128'>
+ <var-decl name='m2' type-id='type-id-15' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='192'>
+ <var-decl name='m3' type-id='type-id-16' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='256'>
+ <var-decl name='m4' type-id='type-id-7' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='576'>
+ <var-decl name='m5' type-id='type-id-17' visibility='default'/>
+ </data-member>
+ </class-decl>
+ <typedef-decl name='ANOTHER_ENUM_TYPE' type-id='type-id-2' id='type-id-18'/>
+ <typedef-decl name='ENUM_TYPE' type-id='type-id-4' id='type-id-19'/>
+ <typedef-decl name='foo_type' type-id='type-id-9' id='type-id-20'/>
+ <typedef-decl name='u_type' type-id='type-id-21' id='type-id-22'/>
+ <union-decl name='u_type' size-in-bits='64' visibility='default' id='type-id-21'>
+ <data-member access='public'>
+ <var-decl name='m0' type-id='type-id-23' visibility='default'/>
+ </data-member>
+ <data-member access='public'>
+ <var-decl name='m1' type-id='type-id-24' visibility='default'/>
+ </data-member>
+ </union-decl>
+ <type-decl name='unsigned char' size-in-bits='8' id='type-id-25'/>
+ <type-decl name='unsigned int' size-in-bits='32' id='type-id-26'/>
+ <pointer-type-def type-id='type-id-18' size-in-bits='64' id='type-id-24'/>
+ <pointer-type-def type-id='type-id-19' size-in-bits='64' id='type-id-23'/>
+ <qualified-type-def type-id='type-id-20' const='yes' id='type-id-27'/>
+ <pointer-type-def type-id='type-id-27' size-in-bits='64' id='type-id-28'/>
+ <qualified-type-def type-id='type-id-12' const='yes' id='type-id-29'/>
+ <pointer-type-def type-id='type-id-29' size-in-bits='64' id='type-id-13'/>
+ <qualified-type-def type-id='type-id-22' const='yes' id='type-id-30'/>
+ <qualified-type-def type-id='type-id-25' const='yes' id='type-id-31'/>
+ <pointer-type-def type-id='type-id-26' size-in-bits='64' id='type-id-15'/>
+ <qualified-type-def type-id='type-id-1' volatile='yes' id='type-id-32'/>
+ <pointer-type-def type-id='type-id-32' size-in-bits='64' id='type-id-14'/>
+ <qualified-type-def type-id='type-id-30' volatile='yes' id='type-id-33'/>
+ <pointer-type-def type-id='type-id-33' size-in-bits='64' id='type-id-17'/>
+ <qualified-type-def type-id='type-id-31' volatile='yes' id='type-id-34'/>
+ <pointer-type-def type-id='type-id-34' size-in-bits='64' id='type-id-16'/>
+ <var-decl name='foos' type-id='type-id-10' mangled-name='foos' visibility='default' elf-symbol-id='foos'/>
+ <function-decl name='fn0' mangled-name='fn0' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='fn0'>
+ <parameter type-id='type-id-28' name='p'/>
+ <return type-id='type-id-35'/>
+ </function-decl>
+ <type-decl name='void' id='type-id-35'/>
+ <function-type size-in-bits='64' id='type-id-36'>
+ <parameter type-id='type-id-28' name='p'/>
+ <return type-id='type-id-35'/>
+ </function-type>
+ </abi-instr>
+</abi-corpus>
new file mode 100644
@@ -0,0 +1,20 @@
+/*
+ * Compile this to emit BTF debug info with:
+ *
+ * gcc -c -gbtf test0.c
+ */
+
+struct S;
+typedef struct S S;
+
+union U;
+typedef union U U;
+
+S*
+fn0(S* p, U* u)
+{
+ if (u)
+ ;
+
+ return p;
+}
new file mode 100644
GIT binary patch
literal 1536
zcmbtUJ8u&~5T3h)*no{fM1d5Fqr#EmJ^Lz?0vW6%7J?`;xIz)Rv(Jy<m+sb5f`sTm
z77hP^zY>Xt-#|}A16?|p@4V|QC)2>3W_RYB*Lr5xZ+D;U*_K6`EP6nfnnsDv?Mu0u
zh*io{j+*t^xBBeOMSV8?QU9=earF7qcZ+T-=LzrN2D8eVSz~#HnJEkGN+Qzx4DVp3
ztg=J4bz$D~@I7G0e#or+St5Itm#dJ7a;QPi_-pdl8I{QGjfbJz9=A{WZnrPpK|k<=
ze%J30+(33*8OAbp+rIP@u^5GZyQmFi(Za8o67AP&J5FK$pt<FgJ>iM6<CQ$GR4Lzg
z3XQPs)P1Q8MQ;m7Ai}8}W}KJ<$tLR@m?lf<y63l)!Ft^w>vY}P%w@74*?5O>FlYnI
z!yD`G>{@>9DLX*_3nA|+{rt7eyrO4f7}3EE15awfjuxR4=q8hcg$dKq6G{LPpADrS
zkcee8-+Nk;;i)8nE|Uo2n8c&!dn8)p;V>MrVKkPZ;2srY>9<}fy*rwUNi?2>kvt<2
zg#%xNy_cQHABIV}|6MjY0eY0&7$aF#$&25wboiQdmla^fjZMtB@yjS3e~+CozkiM2
z=Gb&j)YbLBLNO@qTV@-uWT=MUwsLe045E(L`;LK`t}nEM2`=${%otwrA9slLV-=r1
zSNg68DrY(#Zw6GEZ;Le@f5aBN$LhjkE>u)P{ZDp{VZ`cqjiXGuHZpus^^c)2U1!FO
j)A4w3>De<x1(h@p#UPb-f!t(iS^S}jA1plQLOT98Bq(pA
literal 0
HcmV?d00001
@@ -0,0 +1,23 @@
+<abi-corpus version='2.1' path='data/test-read-btf/test1.o'>
+ <elf-function-symbols>
+ <elf-symbol name='fn0' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ </elf-function-symbols>
+ <abi-instr address-size='64'>
+ <typedef-decl name='S' type-id='type-id-1' id='type-id-2'/>
+ <typedef-decl name='U' type-id='type-id-3' id='type-id-4'/>
+ <pointer-type-def type-id='type-id-2' size-in-bits='64' id='type-id-5'/>
+ <pointer-type-def type-id='type-id-4' size-in-bits='64' id='type-id-6'/>
+ <function-decl name='fn0' mangled-name='fn0' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='fn0'>
+ <parameter type-id='type-id-5' name='p'/>
+ <parameter type-id='type-id-6' name='u'/>
+ <return type-id='type-id-5'/>
+ </function-decl>
+ <class-decl name='S' size-in-bits='48' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-1'/>
+ <union-decl name='U' visibility='default' is-declaration-only='yes' id='type-id-3'/>
+ <function-type size-in-bits='64' id='type-id-7'>
+ <parameter type-id='type-id-5' name='p'/>
+ <parameter type-id='type-id-6' name='u'/>
+ <return type-id='type-id-5'/>
+ </function-type>
+ </abi-instr>
+</abi-corpus>
@@ -471,6 +471,30 @@ InOutSpec in_out_specs[] =
"data/test-abidiff-exit/test-rhbz2114909-report-1.txt",
"output/test-abidiff-exit/test-rhbz2114909-report-1.txt"
},
+#ifdef WITH_BTF
+ {
+ "data/test-abidiff-exit/btf/test0-v0.o",
+ "data/test-abidiff-exit/btf/test0-v1.o",
+ "",
+ "",
+ "",
+ "--no-default-suppression --btf",
+ abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+ "data/test-abidiff-exit/btf/test0-report-1.txt",
+ "output/test-abidiff-exit/btf/test0-report-1.txt"
+ },
+ {
+ "data/test-abidiff-exit/btf/test0-v0.o",
+ "data/test-abidiff-exit/btf/test0-v1.o",
+ "",
+ "",
+ "",
+ "--no-default-suppression --harmless --btf",
+ abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+ "data/test-abidiff-exit/btf/test0-report-2.txt",
+ "output/test-abidiff-exit/btf/test0-report-2.txt"
+ },
+#endif
{0, 0, 0 ,0, 0, 0, abigail::tools_utils::ABIDIFF_OK, 0, 0}
};
new file mode 100644
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// -*- Mode: C++ -*-
+//
+// Copyright (C) 2022 Red Hat, Inc.
+//
+// Author: Dodji Seketeli
+
+/// @file
+///
+/// This file is part of the BTF testsuite. It reads ELF binaries
+/// containing BTF, save them in XML corpus files and diff the
+/// corpus files against reference XML corpus files.
+
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+#include "abg-btf-reader.h"
+#include "test-read-common.h"
+
+using std::string;
+using std::cerr;
+using std::vector;
+
+using abigail::tests::read_common::InOutSpec;
+using abigail::tests::read_common::test_task;
+using abigail::tests::read_common::display_usage;
+using abigail::tests::read_common::options;
+
+using abigail::btf::create_reader;
+using abigail::xml_writer::SEQUENCE_TYPE_ID_STYLE;
+using abigail::xml_writer::HASH_TYPE_ID_STYLE;
+using abigail::tools_utils::emit_prefix;
+
+static InOutSpec in_out_specs[] =
+{
+ {
+ "data/test-read-btf/test0.o",
+ "",
+ "",
+ SEQUENCE_TYPE_ID_STYLE,
+ "data/test-read-btf/test0.o.abi",
+ "output/test-read-btf/test0.o.abi",
+ "--btf",
+ },
+ {
+ "data/test-read-btf/test1.o",
+ "",
+ "",
+ SEQUENCE_TYPE_ID_STYLE,
+ "data/test-read-btf/test1.o.abi",
+ "output/test-read-btf/test1.o.abi",
+ "--btf",
+ },
+ // This should be the last entry.
+ {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL, NULL}
+};
+
+/// Task specialization to perform BTF tests.
+struct test_task_btf : public test_task
+{
+ test_task_btf(const InOutSpec &s,
+ string& a_out_abi_base,
+ string& a_in_elf_base,
+ string& a_in_abi_base);
+ virtual void
+ perform();
+
+ virtual
+ ~test_task_btf()
+ {}
+}; // end struct test_task_btf
+
+/// Constructor.
+///
+/// Task to be executed for each BTF test entry in @ref
+/// abigail::tests::read_common::InOutSpec.
+/// @param InOutSpec the array containing set of tests.
+///
+/// @param a_out_abi_base the output base directory for abixml files.
+///
+/// @param a_in_elf_base the input base directory for object files.
+///
+/// @param a_in_elf_base the input base directory for expected
+/// abixml files.
+test_task_btf::test_task_btf(const InOutSpec &s,
+ string& a_out_abi_base,
+ string& a_in_elf_base,
+ string& a_in_abi_base)
+ : test_task(s, a_out_abi_base, a_in_elf_base, a_in_abi_base)
+ {}
+
+/// The thread function to execute each BTF test entry in @ref
+/// abigail::tests::read_common::InOutSpec.
+///
+/// This reads the corpus into memory, saves it to disk, loads it
+/// again and compares the new in-memory representation against the
+void
+test_task_btf::perform()
+{
+ abigail::ir::environment env;
+
+ set_in_elf_path();
+ set_in_suppr_spec_path();
+
+ abigail::fe_iface::status status =
+ abigail::fe_iface::STATUS_UNKNOWN;
+ vector<char**> di_roots;
+ ABG_ASSERT(abigail::tools_utils::file_exists(in_elf_path));
+
+ abigail::elf_based_reader_sptr rdr = abigail::btf::create_reader(in_elf_path,
+ di_roots, env);
+ ABG_ASSERT(rdr);
+
+ corpus_sptr corp = rdr->read_corpus(status);
+
+ // if there is no output and no input, assume that we do not care about the
+ // actual read result, just that it succeeded.
+ if (!spec.in_abi_path && !spec.out_abi_path)
+ {
+ // Phew! we made it here and we did not crash! yay!
+ return;
+ }
+ if (!corp)
+ {
+ error_message = string("failed to read ") + in_elf_path + "\n";
+ is_ok = false;
+ return;
+ }
+ corp->set_path(spec.in_elf_path);
+ // Do not take architecture names in comparison so that these
+ // test input binaries can come from whatever arch the
+ // programmer likes.
+ corp->set_architecture_name("");
+
+ if (!(is_ok = set_out_abi_path()))
+ return;
+
+ if (!(is_ok = serialize_corpus(out_abi_path, corp)))
+ return;
+
+ if (!(is_ok = run_abidw("--btf ")))
+ return;
+
+ if (!(is_ok = run_diff()))
+ return;
+}
+
+/// Create a new BTF instance for task to be execute by the testsuite.
+///
+/// @param s the @ref abigail::tests::read_common::InOutSpec
+/// tests container.
+///
+/// @param a_out_abi_base the output base directory for abixml files.
+///
+/// @param a_in_elf_base the input base directory for object files.
+///
+/// @param a_in_abi_base the input base directory for abixml files.
+///
+/// @return abigail::tests::read_common::test_task instance.
+static test_task*
+new_task(const InOutSpec* s, string& a_out_abi_base,
+ string& a_in_elf_base, string& a_in_abi_base)
+{
+ return new test_task_btf(*s, a_out_abi_base,
+ a_in_elf_base, a_in_abi_base);
+}
+
+int
+main(int argc, char *argv[])
+{
+ options opts;
+ if (!parse_command_line(argc, argv, opts))
+ {
+ if (!opts.wrong_option.empty())
+ emit_prefix(argv[0], cerr)
+ << "unrecognized option: " << opts.wrong_option << "\n";
+ display_usage(argv[0], cerr);
+ return 1;
+ }
+
+ // compute number of tests to be executed.
+ const size_t num_tests = sizeof(in_out_specs) / sizeof(InOutSpec) - 1;
+
+ return run_tests(num_tests, in_out_specs, opts, new_task);
+}
@@ -23,6 +23,10 @@
#include "abg-ctf-reader.h"
#endif
+#ifdef WITH_BTF
+#include "abg-btf-reader.h"
+#endif
+
using std::vector;
using std::string;
using std::ostream;
@@ -121,6 +125,9 @@ struct options
#endif
#ifdef WITH_CTF
bool use_ctf;
+#endif
+#ifdef WITH_BTF
+ bool use_btf;
#endif
vector<char*> di_root_paths1;
vector<char*> di_root_paths2;
@@ -170,6 +177,10 @@ struct options
,
use_ctf()
#endif
+#ifdef WITH_BTF
+ ,
+ use_btf()
+#endif
#ifdef WITH_DEBUG_SELF_COMPARISON
,
do_debug_self_comparison()
@@ -273,6 +284,9 @@ display_usage(const string& prog_name, ostream& out)
#ifdef WITH_CTF
<< " --ctf use CTF instead of DWARF in ELF files\n"
#endif
+#ifdef WITH_BTF
+ << " --btf use BTF instead of DWARF in ELF files\n"
+#endif
#ifdef WITH_DEBUG_SELF_COMPARISON
<< " --debug-self-comparison debug the process of comparing "
"an ABI corpus against itself"
@@ -639,6 +653,10 @@ parse_command_line(int argc, char* argv[], options& opts)
else if (!strcmp(argv[i], "--ctf"))
opts.use_ctf = true;
#endif
+#ifdef WITH_BTF
+ else if (!strcmp(argv[i], "--btf"))
+ opts.use_btf = true;
+#endif
#ifdef WITH_DEBUG_SELF_COMPARISON
else if (!strcmp(argv[i], "--debug-self-comparison"))
opts.do_debug_self_comparison = true;
@@ -1232,6 +1250,10 @@ main(int argc, char* argv[])
#ifdef WITH_CTF
if (opts.use_ctf)
requested_fe_kind = corpus::CTF_ORIGIN;
+#endif
+#ifdef WITH_BTF
+ if (opts.use_btf)
+ requested_fe_kind = corpus::BTF_ORIGIN;
#endif
abigail::elf_based_reader_sptr rdr =
create_best_elf_based_reader(opts.file1,
@@ -1305,6 +1327,10 @@ main(int argc, char* argv[])
#ifdef WITH_CTF
if (opts.use_ctf)
requested_fe_kind = corpus::CTF_ORIGIN;
+#endif
+#ifdef WITH_BTF
+ if (opts.use_btf)
+ requested_fe_kind = corpus::BTF_ORIGIN;
#endif
abigail::elf_based_reader_sptr rdr =
create_best_elf_based_reader(opts.file2,
@@ -29,6 +29,9 @@
#ifdef WITH_CTF
#include "abg-ctf-reader.h"
#endif
+#ifdef WITH_BTF
+#include "abg-btf-reader.h"
+#endif
#include "abg-writer.h"
#include "abg-reader.h"
#include "abg-comparison.h"
@@ -103,6 +106,9 @@ struct options
bool noout;
#ifdef WITH_CTF
bool use_ctf;
+#endif
+#ifdef WITH_BTF
+ bool use_btf;
#endif
bool show_locs;
bool abidiff;
@@ -144,6 +150,9 @@ struct options
noout(),
#ifdef WITH_CTF
use_ctf(false),
+#endif
+#ifdef WITH_BTF
+ use_btf(false),
#endif
show_locs(true),
abidiff(),
@@ -234,6 +243,9 @@ display_usage(const string& prog_name, ostream& out)
"speed-up the analysis of the binary\n"
<< " --no-assume-odr-for-cplusplus do not assume the ODR to speed-up the "
"analysis of the binary\n"
+#ifdef WITH_BTF
+ << " --btf use BTF instead of DWARF in ELF files\n"
+#endif
<< " --annotate annotate the ABI artifacts emitted in the output\n"
<< " --stats show statistics about various internal stuff\n"
<< " --verbose show verbose messages about internal stuff\n";
@@ -335,6 +347,10 @@ parse_command_line(int argc, char* argv[], options& opts)
#ifdef WITH_CTF
else if (!strcmp(argv[i], "--ctf"))
opts.use_ctf = true;
+#endif
+#ifdef WITH_BTF
+ else if (!strcmp(argv[i], "--btf"))
+ opts.use_btf = true;
#endif
else if (!strcmp(argv[i], "--no-architecture"))
opts.write_architecture = false;
@@ -588,6 +604,10 @@ load_corpus_and_write_abixml(char* argv[],
if (opts.use_ctf)
requested_fe_kind = corpus::CTF_ORIGIN;
#endif
+#ifdef WITH_BTF
+ if (opts.use_btf)
+ requested_fe_kind = corpus::BTF_ORIGIN;
+#endif
// First of all, create a reader to read the ABI from the file
// specfied in opts ...
@@ -93,6 +93,9 @@
#ifdef WITH_CTF
#include "abg-ctf-reader.h"
#endif
+#ifdef WITH_BTF
+#include "abg-btf-reader.h"
+#endif
using std::cout;
using std::cerr;
@@ -212,6 +215,9 @@ public:
#ifdef WITH_CTF
bool use_ctf;
#endif
+#ifdef WITH_BTF
+ bool use_btf;
+#endif
vector<string> kabi_whitelist_packages;
vector<string> suppression_paths;
@@ -256,6 +262,10 @@ public:
#ifdef WITH_CTF
,
use_ctf()
+#endif
+#ifdef WITH_BTF
+ ,
+ use_btf()
#endif
{
// set num_workers to the default number of threads of the
@@ -905,6 +915,9 @@ display_usage(const string& prog_name, ostream& out)
"binaries inside the input package against their ABIXML representation\n"
#ifdef WITH_CTF
<< " --ctf use CTF instead of DWARF in ELF files\n"
+#endif
+#ifdef WITH_BTF
+ << " --btf use BTF instead of DWARF in ELF files\n"
#endif
<< " --help|-h display this help message\n"
<< " --version|-v display program version information"
@@ -1353,6 +1366,10 @@ compare(const elf_file& elf1,
#ifdef WITH_CTF
if (opts.use_ctf)
requested_fe_kind = corpus::CTF_ORIGIN;
+#endif
+#ifdef WITH_BTF
+ if (opts.use_btf)
+ requested_fe_kind = corpus::BTF_ORIGIN;
#endif
abigail::elf_based_reader_sptr reader =
create_best_elf_based_reader(elf1.path,
@@ -1414,6 +1431,11 @@ compare(const elf_file& elf1,
if (opts.use_ctf)
;
else
+#endif
+#ifdef WITH_BTF
+ if (opts.use_btf)
+ ;
+ else
#endif
reader->refers_to_alt_debug_info(alt_di_path);
if (!alt_di_path.empty())
@@ -1449,10 +1471,16 @@ compare(const elf_file& elf1,
corpus_sptr corpus2;
{
corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
+
#ifdef WITH_CTF
if (opts.use_ctf)
requested_fe_kind = corpus::CTF_ORIGIN;
#endif
+#ifdef WITH_BTF
+ if (opts.use_btf)
+ requested_fe_kind = corpus::BTF_ORIGIN;
+#endif
+
abigail::elf_based_reader_sptr reader =
create_best_elf_based_reader(elf2.path,
di_dirs2,
@@ -1513,6 +1541,11 @@ compare(const elf_file& elf1,
if (opts.use_ctf)
;
else
+#endif
+#ifdef WITH_BTF
+ if (opts.use_btf)
+ ;
+ else
#endif
reader->refers_to_alt_debug_info(alt_di_path);
if (!alt_di_path.empty())
@@ -1617,6 +1650,10 @@ compare_to_self(const elf_file& elf,
#ifdef WITH_CTF
if (opts.use_ctf)
requested_fe_kind = corpus::CTF_ORIGIN;
+#endif
+#ifdef WITH_BTF
+ if (opts.use_btf)
+ requested_fe_kind = corpus::BTF_ORIGIN;
#endif
abigail::elf_based_reader_sptr reader =
create_best_elf_based_reader(elf.path,
@@ -3044,14 +3081,24 @@ compare_prepared_linux_kernel_packages(package& first_package,
suppressions_type supprs;
corpus_group_sptr corpus1, corpus2;
+
+ corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
+#ifdef WITH_CTF
+ if (opts.use_ctf)
+ requested_fe_kind = corpus::CTF_ORIGIN;
+#endif
+#ifdef WITH_BTF
+ if (opts.use_btf)
+ requested_fe_kind = corpus::BTF_ORIGIN;
+#endif
+
corpus1 = build_corpus_group_from_kernel_dist_under(dist_root1,
debug_dir1,
vmlinux_path1,
opts.suppression_paths,
opts.kabi_whitelist_paths,
- supprs,
- opts.verbose,
- env);
+ supprs, opts.verbose,
+ env, requested_fe_kind);
if (!corpus1)
return abigail::tools_utils::ABIDIFF_ERROR;
@@ -3061,9 +3108,8 @@ compare_prepared_linux_kernel_packages(package& first_package,
vmlinux_path2,
opts.suppression_paths,
opts.kabi_whitelist_paths,
- supprs,
- opts.verbose,
- env);
+ supprs, opts.verbose,
+ env, requested_fe_kind);
if (!corpus2)
return abigail::tools_utils::ABIDIFF_ERROR;
@@ -3434,6 +3480,10 @@ parse_command_line(int argc, char* argv[], options& opts)
#ifdef WITH_CTF
else if (!strcmp(argv[i], "--ctf"))
opts.use_ctf = true;
+#endif
+#ifdef WITH_BTF
+ else if (!strcmp(argv[i], "--btf"))
+ opts.use_btf = true;
#endif
else if (!strcmp(argv[i], "--help")
|| !strcmp(argv[i], "-h"))
@@ -63,6 +63,9 @@ struct options
optional<bool> exported_interfaces_only;
#ifdef WITH_CTF
bool use_ctf;
+#endif
+#ifdef WITH_BTF
+ bool use_btf;
#endif
string wrong_option;
string kernel_dist_root1;
@@ -88,6 +91,10 @@ struct options
#ifdef WITH_CTF
,
use_ctf(false)
+#endif
+#ifdef WITH_BTF
+ ,
+ use_btf(false)
#endif
{}
}; // end struct options.
@@ -117,6 +124,9 @@ display_usage(const string& prog_name, ostream& out)
"whitelist\n"
#ifdef WITH_CTF
<< " --ctf use CTF instead of DWARF in ELF files\n"
+#endif
+#ifdef WITH_BTF
+ << " --btf use BTF instead of DWARF in ELF files\n"
#endif
<< " --impacted-interfaces|-i show interfaces impacted by ABI changes\n"
<< " --full-impact|-f show the full impact of changes on top-most "
@@ -259,6 +269,10 @@ parse_command_line(int argc, char* argv[], options& opts)
#ifdef WITH_CTF
else if (!strcmp(argv[i], "--ctf"))
opts.use_ctf = true;
+#endif
+#ifdef WITH_BTF
+ else if (!strcmp(argv[i], "--btf"))
+ opts.use_btf = true;
#endif
else if (!strcmp(argv[i], "--impacted-interfaces")
|| !strcmp(argv[i], "-i"))
@@ -421,11 +435,15 @@ main(int argc, char* argv[])
corpus_group_sptr group1, group2;
string debug_info_root_dir;
- corpus::origin requested_fe_kind =
+ corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
#ifdef WITH_CTF
- opts.use_ctf ? corpus::CTF_ORIGIN :
+ if (opts.use_ctf)
+ requested_fe_kind = corpus::CTF_ORIGIN;
+#endif
+#ifdef WITH_BTF
+ if (opts.use_btf)
+ requested_fe_kind = corpus::BTF_ORIGIN;
#endif
- corpus::DWARF_ORIGIN;
if (!opts.kernel_dist_root1.empty())
{