From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id B21993858D33 for ; Fri, 6 Jan 2023 20:39:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B21993858D33 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1673037584; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type; bh=4A1sK1DQB93J1+9PX5h34F9vtW1ubxUJEoi7RotO/Ew=; b=GUiIC8LB4+DUYuJvhtlN358/3NWS5odd41aKEYn6oE1YoLmQPWFwEUi2ICnOUofK5eRSfa veuRheZh7d5kSUFVXOA8qvyssvP047sLPRHWWMrLjzTzEQ6NsYw/QGQrSIl/ir9k2xsbsl avrfeVNjG87ILpZlcoO2GtrFVCbL990= Received: from mail-qv1-f69.google.com (mail-qv1-f69.google.com [209.85.219.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-151-xuMHsbYuOZiszt8CFPyXsA-1; Fri, 06 Jan 2023 15:39:43 -0500 X-MC-Unique: xuMHsbYuOZiszt8CFPyXsA-1 Received: by mail-qv1-f69.google.com with SMTP id ob12-20020a0562142f8c00b004c6c72bf1d0so1280455qvb.9 for ; Fri, 06 Jan 2023 12:39:43 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:message-id:date:organization:subject:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=4A1sK1DQB93J1+9PX5h34F9vtW1ubxUJEoi7RotO/Ew=; b=tO8t1+eFSxTu7+0iWMk8qZyI1Icguiro1a4aec7iopVcrwtLeNwg0tb9QL+Vg8CtUf MwTLXzpfzJCMD951zZ0HZ2jF4HnPqAesZ7pkGqeSTADcj6MEsjcDpn1yJF4Rt0TVJFa0 dgx4x/Aa8+wnfsdfhrTbS5UvmzguIPSrYnhYLo5qpcnkbj9g7KjaISRMIBxFgDIw4Hb0 QZhm5GtIYb+dnG9ljrF0tnduZTr8t23QpMR1FIyJxOVmYqu+wSFCV8VXeG3BI9V1TepI EXiwbCQQGDI6n59YohgoPcjZ92dwlVCGevofXtKbKIEtAsXBPQ+05qG/GZBc5TCS8/05 IMVQ== X-Gm-Message-State: AFqh2kptEyIXoMhu8r5ZmNFo+0eqYzON/Y3o89t6JGC4ny792BFypvuL h0FbquJei8NtI5j8WUaAmoYzw2pAcnj7efIexkZWDJxt1P3cfOLN5S/d5qTwa8+8guF2Tq/qbbD 0vqOTDn7/p5DL7tpOv/ptUj2HC6leRquEkmSXtJWToPCU9AoJxNwVpJizvHc+A9hwVAAy X-Received: by 2002:ac8:6759:0:b0:39c:da20:626 with SMTP id n25-20020ac86759000000b0039cda200626mr87963451qtp.48.1673037580438; Fri, 06 Jan 2023 12:39:40 -0800 (PST) X-Google-Smtp-Source: AMrXdXuIHB2HJQUycy/awaQlkfPIe53k4cSZWjHI5vtKzSJc+CtRoMyzBTViLT/nwzgDAKkBTGw7fw== X-Received: by 2002:ac8:6759:0:b0:39c:da20:626 with SMTP id n25-20020ac86759000000b0039cda200626mr87963284qtp.48.1673037578221; Fri, 06 Jan 2023 12:39:38 -0800 (PST) Received: from localhost ([88.120.130.27]) by smtp.gmail.com with ESMTPSA id u8-20020a37ab08000000b00702311aea78sm1047084qke.82.2023.01.06.12.39.37 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 06 Jan 2023 12:39:37 -0800 (PST) Received: by localhost (Postfix, from userid 1000) id 0E5D2581C59; Fri, 6 Jan 2023 21:39:34 +0100 (CET) From: Dodji Seketeli To: libabigail@sourceware.org Subject: [PATCH, applied] Add support for BTF Organization: Red Hat / France X-Operating-System: Fedora 38 X-URL: http://www.redhat.com Date: Fri, 06 Jan 2023 21:39:34 +0100 Message-ID: <87pmbrl7nd.fsf@redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.1 (gnu/linux) MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain X-Spam-Status: No, score=-11.6 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Hello, This patch adds support for the BTF debug information format. It provides a new BTF front-end which can be instantiated by the function tools::create_best_elf_based_reader(). For now, the BTF front-end supports the basic types (integers, pointers, qualified types, typedefs, struct and unions and function pointers) for functions and variables as emitted for the C language by GCC. It seems to be able to support the BTF debug information emitted for the vmlinux kernel by the pahole tool as well. When configured with the --enable-btf option, the WITH_BTF pre-processor macro is defined, enabling the BTF support. That option is turned on by default if the /usr/include/bpf/btf.h header is found on the system. To disable this, one can use the --disable-btf option. The abidw and abidiff programs have been adapted to use the BTF front-end when provided with the '--btf' option, or if BTF debug information is the only one present in the binary. * configure.ac: If the header /usr/include/bpf/btf.h exists, then define the WITH_BTF pre-processor macro, unless --disable-btf was provided. * doc/manuals/abidiff.rst: Document the new --btf option. * doc/manuals/abidw.rst: Likewise. * doc/manuals/kmidiff.rst: Likewise. * doc/manuals/abipkgdiff.rst: Likewise. * include/abg-btf-reader.h: New header file. Contains the declaration of the new btf::reader class. * src/abg-btf-reader.cc: New source file. Contains the definitions of the new btf::reader class. * include/Makefile.am: Add the new include/abg-btf-reader.h header file to source distribution. * include/abg-corpus.h (enum origin): Add a new BTF_ORIGIN enumerator. * include/abg-tools-utils.h (file_has_btf_debug_info): Declare new function. * src/abg-tools-utils.cc (file_has_btf_debug_info): Define new function. (create_best_elf_based_reader): Adapt to support BTF input. If the user requested the BTF front-end, instantiate it. Otherwise, if the input file has only BTF debug info, instantiate the BTF front end. * include/abg-elf-reader.h (elf::reader::find_btf_section): Declare new member function. (elf::reader::{function, variable}_symbol_is_exported): Add new overloads. * src/abg-elf-reader.cc (reader::priv::btf_section): New data member. (reader::find_btf_section): Define new member function. * src/Makefile.am: Add the new abg-ctf-reader.cc file to source distribution. * tools/abidw.cc (options::use_btf): New data member. (display_usage): Add a help string for the new --btf option. (parse_command_line): Support the new --btf option. (load_corpus_and_write_abixml): If the user asked to use the btf front-end then use that one. * tools/abidiff.cc (options::use_btf): New data member. (options::options): Initialize it. (display_usage):: Add a help string to the new --btf options. (parse_command_line): Support the new --btf options. (main): If the user asked to use the btf front-end, then use that one. * tools/abidw.cc (options::use_btf): New data member. (options::options): Initialize it. (parse_command_line): Add a help string to the new --btf options. (load_corpus_and_write_abixml): If the user asked to use the btf front-end, then use that one. * tools/kmidiff.cc (options::use_btf): New data member. (options::options): Initialize it. (display_usage): Add a help string to the new --btf options. (parse_command_line): Add a help string to the new --btf options. (main): If the user asked to use the btf front-end, then use that one. * tools/abipkgdiff.cc (options::use_btf): New data member. (options::options): Initialize it. (display_usage): Add a help string to the new --btf options. (parse_command_line): Add a help string to the new --btf options. (compare, compare_to_self) (compare_prepared_linux_kernel_packages): If the user asked to use the btf front-end, then use that one. * tests/data/test-read-btf/test{0,1}.o: New binary test input file. * tests/data/test-read-btf/test{0,1}.c: Source code of the binary input file above. * tests/data/test-read-btf/test{0,1}.o.abi: Reference ABIXML output. * tests/data/test-abidiff-exit/btf/test0-report-{1,2}.txt: New test reference output. * tests/data/test-abidiff-exit/btf/test0-v{0,1}.o: New binary test input. * tests/data/test-abidiff-exit/btf/test0-v{0,1}.c: The source files of the binary inputs above. * tests/test-read-btf.cc: New test file to run the btf/abixml tests. * tests/Makefile.am: Add the new test files to the source distribution. Signed-off-by: Dodji Seketeli --- configure.ac | 81 +- doc/manuals/abidiff.rst | 11 +- doc/manuals/abidw.rst | 9 +- doc/manuals/abipkgdiff.rst | 16 +- doc/manuals/kmidiff.rst | 19 +- include/Makefile.am | 4 + include/abg-btf-reader.h | 34 + include/abg-corpus.h | 3 +- include/abg-elf-reader.h | 6 + include/abg-tools-utils.h | 2 + src/Makefile.am | 4 + src/abg-btf-reader.cc | 1102 +++++++++++++++++ src/abg-elf-reader.cc | 22 + src/abg-tools-utils.cc | 46 + tests/Makefile.am | 11 + tests/data/Makefile.am | 13 + .../test-abidiff-exit/btf/test0-report-1.txt | 16 + .../test-abidiff-exit/btf/test0-report-2.txt | 53 + tests/data/test-abidiff-exit/btf/test0-v0.c | 40 + tests/data/test-abidiff-exit/btf/test0-v0.o | Bin 0 -> 2320 bytes tests/data/test-abidiff-exit/btf/test0-v1.c | 45 + tests/data/test-abidiff-exit/btf/test0-v1.o | Bin 0 -> 2376 bytes tests/data/test-read-btf/test0.c | 40 + tests/data/test-read-btf/test0.o | Bin 0 -> 2312 bytes tests/data/test-read-btf/test0.o.abi | 90 ++ tests/data/test-read-btf/test1.c | 20 + tests/data/test-read-btf/test1.o | Bin 0 -> 1536 bytes tests/data/test-read-btf/test1.o.abi | 23 + tests/test-abidiff-exit.cc | 24 + tests/test-read-btf.cc | 188 +++ tools/abidiff.cc | 26 + tools/abidw.cc | 20 + tools/abipkgdiff.cc | 62 +- tools/kmidiff.cc | 24 +- 34 files changed, 2026 insertions(+), 28 deletions(-) create mode 100644 include/abg-btf-reader.h create mode 100644 src/abg-btf-reader.cc create mode 100644 tests/data/test-abidiff-exit/btf/test0-report-1.txt create mode 100644 tests/data/test-abidiff-exit/btf/test0-report-2.txt create mode 100644 tests/data/test-abidiff-exit/btf/test0-v0.c create mode 100644 tests/data/test-abidiff-exit/btf/test0-v0.o create mode 100644 tests/data/test-abidiff-exit/btf/test0-v1.c create mode 100644 tests/data/test-abidiff-exit/btf/test0-v1.o create mode 100644 tests/data/test-read-btf/test0.c create mode 100644 tests/data/test-read-btf/test0.o create mode 100644 tests/data/test-read-btf/test0.o.abi create mode 100644 tests/data/test-read-btf/test1.c create mode 100644 tests/data/test-read-btf/test1.o create mode 100644 tests/data/test-read-btf/test1.o.abi create mode 100644 tests/test-read-btf.cc diff --git a/configure.ac b/configure.ac index a009fbc6..d2896020 100644 --- a/configure.ac +++ b/configure.ac @@ -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 ]) + + 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 ]) + + 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 ]) + 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 ]) + 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 ]) + 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} diff --git a/doc/manuals/abidiff.rst b/doc/manuals/abidiff.rst index dd357fba..2debc20d 100644 --- a/doc/manuals/abidiff.rst +++ b/doc/manuals/abidiff.rst @@ -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 diff --git a/doc/manuals/abidw.rst b/doc/manuals/abidw.rst index 87db1890..93eced71 100644 --- a/doc/manuals/abidw.rst +++ b/doc/manuals/abidw.rst @@ -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 diff --git a/doc/manuals/abipkgdiff.rst b/doc/manuals/abipkgdiff.rst index 9d7a3973..d448ad3e 100644 --- a/doc/manuals/abipkgdiff.rst +++ b/doc/manuals/abipkgdiff.rst @@ -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 diff --git a/doc/manuals/kmidiff.rst b/doc/manuals/kmidiff.rst index a27d2456..40358b92 100644 --- a/doc/manuals/kmidiff.rst +++ b/doc/manuals/kmidiff.rst @@ -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 diff --git a/include/Makefile.am b/include/Makefile.am index 6b7f1e49..22f7151d 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -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 diff --git a/include/abg-btf-reader.h b/include/abg-btf-reader.h new file mode 100644 index 00000000..c85ff9bd --- /dev/null +++ b/include/abg-btf-reader.h @@ -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& 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__ diff --git a/include/abg-corpus.h b/include/abg-corpus.h index 90419694..fabda0f9 100644 --- a/include/abg-corpus.h +++ b/include/abg-corpus.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: diff --git a/include/abg-elf-reader.h b/include/abg-elf-reader.h index 2d25b500..9e370c0b 100644 --- a/include/abg-elf-reader.h +++ b/include/abg-elf-reader.h @@ -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& dt_needed()const; diff --git a/include/abg-tools-utils.h b/include/abg-tools-utils.h index ff7618fe..70745b0f 100644 --- a/include/abg-tools-utils.h +++ b/include/abg-tools-utils.h @@ -41,6 +41,8 @@ bool file_has_dwarf_debug_info(const string& elf_file_path, const vector& debug_info_root_paths); bool file_has_ctf_debug_info(const string& elf_file_path, const vector& debug_info_root_paths); +bool file_has_btf_debug_info(const string& elf_file_path, + const vector& debug_info_root_paths); bool is_dir(const string&); bool dir_exists(const string&); bool dir_is_empty(const string &); diff --git a/src/Makefile.am b/src/Makefile.am index 70cc04a5..3044c136 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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) diff --git a/src/abg-btf-reader.cc b/src/abg-btf-reader.cc new file mode 100644 index 00000000..b3bcfe2f --- /dev/null +++ b/src/abg-btf-reader.cc @@ -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 +#include +#include + +#include "abg-elf-helpers.h" + +// +ABG_BEGIN_EXPORT_DECLARATIONS + +#include "abg-btf-reader.h" +#include "abg-ir.h" +#include "abg-tools-utils.h" + +ABG_END_EXPORT_DECLARATIONS +// + +namespace abigail +{ +using namespace ir; + +namespace btf +{ + +class reader; + +/// A convenience typedef for a shared pointer to +/// abigail::btf::reader. +typedef shared_ptr 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 +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 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(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(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& 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& 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& 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(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(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(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(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(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& 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 diff --git a/src/abg-elf-reader.cc b/src/abg-elf-reader.cc index 1f704e3f..57e7f2dc 100644 --- a/src/abg-elf-reader.cc +++ b/src/abg-elf-reader.cc @@ -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& 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. diff --git a/src/abg-tools-utils.cc b/src/abg-tools-utils.cc index db04ccd8..81f9aa75 100644 --- a/src/abg-tools-utils.cc +++ b/src/abg-tools-utils.cc @@ -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& 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) diff --git a/tests/Makefile.am b/tests/Makefile.am index 7c515d35..2c5e7286 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index a7c4502c..a4740e3e 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -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 \ diff --git a/tests/data/test-abidiff-exit/btf/test0-report-1.txt b/tests/data/test-abidiff-exit/btf/test0-report-1.txt new file mode 100644 index 00000000..7533965a --- /dev/null +++ b/tests/data/test-abidiff-exit/btf/test0-report-1.txt @@ -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 + diff --git a/tests/data/test-abidiff-exit/btf/test0-report-2.txt b/tests/data/test-abidiff-exit/btf/test0-report-2.txt new file mode 100644 index 00000000..7bc1f6d0 --- /dev/null +++ b/tests/data/test-abidiff-exit/btf/test0-report-2.txt @@ -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 + diff --git a/tests/data/test-abidiff-exit/btf/test0-v0.c b/tests/data/test-abidiff-exit/btf/test0-v0.c new file mode 100644 index 00000000..5e5bdd57 --- /dev/null +++ b/tests/data/test-abidiff-exit/btf/test0-v0.c @@ -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}; diff --git a/tests/data/test-abidiff-exit/btf/test0-v0.o b/tests/data/test-abidiff-exit/btf/test0-v0.o new file mode 100644 index 0000000000000000000000000000000000000000..42c725d3ff1130e63d6b924480fdfdc75109a827 GIT binary patch literal 2320 zcmbtVOK%)S5U!ax&f3_<3Gal*q&Cy^GHmE`EIVE9hi*{R`M%=Q;n70%H;ZRwa=ep0r{Aw*hy zTuF`#PvpA$B=p~uy~_REQ@X?2)s@aMTbt+h448G%MsO-47;o zM>RR#lfo`ZcNhn$4C7JHJN9L1uSj%Rj%R|B$c=c=k?yD><$fH6A@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 diff --git a/tests/data/test-abidiff-exit/btf/test0-v1.c b/tests/data/test-abidiff-exit/btf/test0-v1.c new file mode 100644 index 00000000..c299b582 --- /dev/null +++ b/tests/data/test-abidiff-exit/btf/test0-v1.c @@ -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}; diff --git a/tests/data/test-abidiff-exit/btf/test0-v1.o b/tests/data/test-abidiff-exit/btf/test0-v1.o new file mode 100644 index 0000000000000000000000000000000000000000..712d6aad6475a71d6f685d85c75ce006914818e2 GIT binary patch literal 2376 zcmbtVOK%%h6h1Re6DP#MEl?ieF)R?RM8@_2Qt1L*BDV&WP=#0(YO8ddj340fSe^+= zkPwj&h$tJDhzeC!qPlbHF0Z8eaNW z#>PEECKbD+3@BUon>PFON0!s?#1Lif;Y@R!ePnFgCt&}R`6c%D-^{ky$697{OnbvU zeH<|QYA?VqW=~dl5Vn$(PoI4K5YR034f_&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(ZPnFsKk2$pAq!6&Iq#I* z{%=z9NP4R7&G1`3Zp8JPJe$W3{}$9)W2w<8HaP7x!VYr~o_Brb(|{ZAgo)o0H%>;G z?rJLuwi9tT{Y3TKeSPhmxEoOz1~>%nAW8xkJzR){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_R4MO6Qkh~ literal 0 HcmV?d00001 diff --git a/tests/data/test-read-btf/test0.c b/tests/data/test-read-btf/test0.c new file mode 100644 index 00000000..5e5bdd57 --- /dev/null +++ b/tests/data/test-read-btf/test0.c @@ -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}; diff --git a/tests/data/test-read-btf/test0.o b/tests/data/test-read-btf/test0.o new file mode 100644 index 0000000000000000000000000000000000000000..81d6fc026098f5deecc8b780b618baefabacc3e3 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#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)dtTxf2G!?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!yAHG`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 diff --git a/tests/data/test-read-btf/test0.o.abi b/tests/data/test-read-btf/test0.o.abi new file mode 100644 index 00000000..165beaee --- /dev/null +++ b/tests/data/test-read-btf/test0.o.abi @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/test-read-btf/test1.c b/tests/data/test-read-btf/test1.c new file mode 100644 index 00000000..adbfb8b3 --- /dev/null +++ b/tests/data/test-read-btf/test1.c @@ -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; +} diff --git a/tests/data/test-read-btf/test1.o b/tests/data/test-read-btf/test1.o new file mode 100644 index 0000000000000000000000000000000000000000..218e2e16f7c9d6ed832060f4f3cf0c3ee9ee3e5a GIT binary patch literal 1536 zcmbtUJ8u&~5T3h)*no{fM1d5Fqr#EmJ^Lz?0vW6%7J?`;xIz)Rv(JyXt-#|}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$ptiM6vY}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 + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test-abidiff-exit.cc b/tests/test-abidiff-exit.cc index e7f02eb5..df2f087c 100644 --- a/tests/test-abidiff-exit.cc +++ b/tests/test-abidiff-exit.cc @@ -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} }; diff --git a/tests/test-read-btf.cc b/tests/test-read-btf.cc new file mode 100644 index 00000000..837fa585 --- /dev/null +++ b/tests/test-read-btf.cc @@ -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 +#include +#include +#include +#include +#include +#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 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); +} diff --git a/tools/abidiff.cc b/tools/abidiff.cc index 91a626a9..bf0bf9fc 100644 --- a/tools/abidiff.cc +++ b/tools/abidiff.cc @@ -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 di_root_paths1; vector 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, diff --git a/tools/abidw.cc b/tools/abidw.cc index 102d3a8c..ddb3846e 100644 --- a/tools/abidw.cc +++ b/tools/abidw.cc @@ -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 ... diff --git a/tools/abipkgdiff.cc b/tools/abipkgdiff.cc index 99fc1a33..c588481c 100644 --- a/tools/abipkgdiff.cc +++ b/tools/abipkgdiff.cc @@ -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 kabi_whitelist_packages; vector 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")) diff --git a/tools/kmidiff.cc b/tools/kmidiff.cc index 76fb9d92..f00895a3 100644 --- a/tools/kmidiff.cc +++ b/tools/kmidiff.cc @@ -63,6 +63,9 @@ struct options optional 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()) { -- 2.39.0 -- Dodji