update version to 2.8

Signed-off-by: lizhenlin <lizhenlin2@h-partners.com>
This commit is contained in:
lizhenlin
2025-11-11 10:34:43 +08:00
parent a22906654c
commit a506c1d186
112 changed files with 37834 additions and 10961 deletions
+3
View File
@@ -20,6 +20,9 @@ config("libabigail_defaults") {
"-Wno-unused-variable",
"-Wno-unused-value",
"-Wno-overloaded-virtual",
"-Wno-defaulted-function-deleted",
"-Wno-parentheses",
"-Wno-infinite-recursion",
]
}
+6797
View File
File diff suppressed because it is too large Load Diff
+10 -3
View File
@@ -21,7 +21,7 @@ autoconf-archive/ax_check_python_modules.m4 \
autoconf-archive/ax_prog_python_version.m4 \
autoconf-archive/ax_compare_version.m4 \
NEWS README LICENSE.txt license-change-2020.txt \
COMPILING COMMIT-LOG-GUIDELINES VISIBILITY \
COMPILING COMMIT-LOG-GUIDELINES VISIBILITY SECURITY \
ChangeLog gen-changelog.py \
$(headers) $(m4data_DATA) \
libabigail.pc.in
@@ -30,7 +30,7 @@ libabigail.pc.in
# Don't make make repeat.
AM_MAKEFLAGS = --no-print-directory
.PHONY: doc
.PHONY: doc big-tests
doc: html-doc man info
@@ -80,7 +80,7 @@ tarball-and-tag-and-upload: tarball-and-all
tarball-and-all: tag-and-all
$(MAKE) tarball
tag-and-all: distcheck check-self-compare
tag-and-all: distcheck full-check
$(MAKE) tag-release-only
# the default for GZIP_ENV is --best, which is pretty slow for check runs
@@ -94,3 +94,10 @@ distcheck-fast:
check-self-compare:
$(MAKE) -C tests check-self-compare
big-tests:
test -d big-tests && $(MAKE) -C big-tests check
clean-big-tests:
test -d big-tests && $(MAKE) -C big-tests clean
full-check: check check-self-compare big-tests
+312
View File
@@ -1,3 +1,315 @@
2.8
===
Dodji Seketeli (30):
ChangeLog: Update for 2.7 release
NEWS: Update for 2.7 release
doc/website/mainpage.txt: Update to 2.7
configure: Bump libabigail version to 2.8
comparison: Emit local diff node category in tree dump
{default,leaf}-reporter: Add incompatible changes to leaf reporter
Bug 32902 - Recognize harmless type size increase
configure: Add --with-libxml2 option
tools-utils: Fix a comment
tools-utils: Fix XZ decompression after all compression data is read
libxml-utils,tools-utils: Add an I/O handler for XZ input in libxml2
Bug 32975 - Filter out replacing a data member with a compatible union
elf-reader: Fix elfutils initialization of debuginfo lookup paths
configure: Remove the unnecessary FOUND_DWARF_GETALT_IN_LIBDW variable
fedabipkgdiff: Fix getting the latest RPM version of a given Fedora distro
Change debuginfo root paths type from vector<char**> to vector<string>
Bug 30329 - Fix regression in support for absolute path to alt DWARF
Bug 33076 - abicompat doesn't filter out harmless diff nodes
test-abicompat: Fix color setting
Improve harmless integral type change filtering
Bug 33055 - classes_have_same_layout & types_are_compatible enter in endless loop
abg-comparison: Do not abort when a static data member is deleted
abg-comparison: Fix indentation
symtab-reader: Add missing space
abidw: Sort options documentation alphabetically
elf-reader,symtab-reader: Fix suppression of aliased symbols
Bug 33090 - Implement abidw --force-early-suppression
tests/data/test-read-dwarf/PR33090: Add missing test material
Bug 26021 - Upgrade the C++ standard to C++14
configure: Bump libabigail_so_current to 7
Frank Ch. Eigler (2):
PR31533: abidb: drop debuginfod-client verbosity env variables
tests/runtestabidb2.sh.in: Take more care while doing cleanup
Mark Wielaard (1):
tests/runtestfedabipkgdiffpy3.sh.in: Don't use which to find python3
2.7
===
Dodji Seketeli (49):
Makefile.am: Update tag-and-all rule to do a full-check
big-tests: Update to commit bd0c1f8909a7b2f5018d54b82f7d6829c4849b59
configure.ac: Bump version number to 2.7
SECURITY: New security policy text
fedabipkgdiff.rst: Sort options documentation alphabetically
fedabipkgdiff: Add a new --private-dso option
abidiff.rst: Fix typo in the doc for --kmi-whitelist
configure: Support using custom builds of elfutils
Bug 32402 - dwarf-reader,ir: Recognize new DWARF 5 languages
Update copyright years for 2025
configure.ac: Add a missing preamble
abipkgdiff: Fix spacing in usage text output
abipkgdiff: Fix indentation
tools-utils: Fix indentation
tools-utils: Add missing comment
abipkgdiff: Add more verbose logging
abipkgdiff: Add new --verbose-diff option
abipkgdiff.rst: Sort options documentation items alphabetically
abipkgdiff: Recognize stablelist files in their package
configure: Fix xxhash detection code
configure: Add $ELF_CFLAGS and $DW_CFLAGS to DEPS_CPPFLAGS
Add support for reading XZ-compressed files
abipkgdiff: Rename whitelist into stablelist
configure: Disable abidb on python version < 3.9
Bug PR32476 - abipkgdiff: Support comparing sets of packages
big-tests: Update to latest commit 2afebc4
{ctf,dwarf}-reader.cc: Fix a virtual method name conflict in elf_base_reader
configure.ac: Add a new --enable-inlined-xxhash option
abipkgdiff: Don't use full Linux kernel pkg path in change reports
big-tests: Sync with libabigail hashe 229682
abipkgdiff: Avoid wrongly considering binaries being added/removed
reporter-priv: Fix a thinko in sub-range change report
comp-filter: Better detection of harmless/harmful enum changes
ir: Better handle int[5][2] changed into int[2][5]
comp-filter,ir: Simplify logic of has_harmless_name_change
ir: Recognize classes of same layout as being compatible
Bug 21296 - Normalize declaration names read from DWARF
Bug 31642 - Categorize incompatible changes on functions and variables
Bug 31642 - Don't forget filtered-out incompatible fns and var changes
Bug 28505 - Fix a case of pointer to void* change filtering
big-test: Update to e772c1e67aba14141dd16735ecdf19368b0cb29e
default.abignore: Improve default suppression for krb5 libraries
rhbz2355363 - abipkgdiff: Don't abort when alternate debug info is not found
manuals/conf.py: Update copyright years in the manuals
abidiff.rst: Sort option documentation bullets in lexicographic order
libabigail-concepts: Document the incompatible changes concept
abg-comp-filter: Fix declaration of has_harmful_name_change
abg-comp-filter: Fix some documentation thinko
manuals: Fix broken links
Bug 32794 - ir: avoid asserting in get_type_name
configure: Bump libabigail_so_current to 6
ChangeLog: Update for 2.7 release
NEWS: Update for 2.7 release
Sam James (1):
configure.ac: fix typos for XXHASH_LIBS, LZMA_LIBS
2.6
===
Claudiu Zissulescu (3):
ctf-reader: Optimize calling sorting function for functions and variables.
ctf-reader: Add time logging to CTF reader
abg-tools-utils: Fix memory corruption when using CTF option
Dodji Seketeli (113):
doc/website/mainpage.txt: Update for 2.5 release
doc/api/libabigail.doxy: Update to newer version.
{ctf,btf}-reader: Document the namespace for nicer apidoc
configure.ac: Update version to 2.6
Update Copyright for year 2024
fedabipkgdiff: Cleanup output of ABI comparison
ir,writer: Fix function type naming & fn type annotation in ABIXML
ir: Make IR node visitor aware of non-canonicalized types
writer: Fix control of emitting parm names in function types
dwarf-reader,ir: Improve detection of method types & implicit parms
dwarf-reader,ir: Merge member fns of classes
test-read-common: Fix error message
Suppress patch file that was wrongly added to the repository
elf-reader: Avoid crashing when looking at non-existing variable symbol
dwarf-reader,ir: Unify type sorting & sort types before c14n
btf-reader: Ignore BTF nodes that ought to be ignored
configure: Fix detection of BTF header to enable the BTF front-end
{btf,dwarf,ctf,abixml}-reader: Fix size of subrange type
Bug 31793 - tools-utils: Avoid endless loop in is_regular_file for directories
tools-utils.cc: Support collecting kernel binary paths build from sources
abidw: make the --lt option support --btf
btf-reader: Fix re-use of the BTF reader for several binaries in a row
ctf-reader: Fix re-initialization of the CTF reader
ir: Cache the pretty representation used during pre-canonicalization type sorting
dwarf-reader: Fix reader::initialize to clear per corpus data
btf-reader: Add missing data members reset to reader::initialize
ir: Fix a potential crash in canonicalize_types
elf-based-reader: Clean up logic of elf_based_reader::read_and_add_corpus_to_group
tools-utils,btf-reader: Take modules into account for corpus group
corpus: Support adding translation units with empty path
ctf-reader: Do not set data member offsets for unions
ctf-reader: During re-initialization, only clear canonicalize-able types
ctf-reader: Fix analyzing single kernel binaries
reader: Fix corpus group reading
reader: Simplify type canonicalization invocation
reader: Simplify logic of get_or_read_and_add_translation_unit
reader: Fix building of void and void pointer types
reader: Fix building of variadic parameter type
ir: Don't strip typedefs from parms and return type when comparing fns
ir: Rename integral_type into real_type
ir,comparison,default-reporter: Consider sub-ranges in array diffs
abidw: Support the --abidiff option for Linux Kernel trees
configure: Support the optional 'big-tests' sub-directory
configure.ac: Fix typo triggered when --enable-big-tests is used
Use smart pointers for variables exported from the ABI corpus
ir: Fix getting the translation unit for an ABI artifact
ir: add_decl_to_scope shouldn't abort on nullptr scopes
ir: Make odr_is_relevant support support artifacts with no TU set yet
ir: Support canonical type adjustments for decl-only class types
ir: Support comparing a class_decl against a class_or_union
ir: Speed up enum comparison
ir: Fix comment for translation_unit::get_global_scope
reader: Avoid crashing on empty scopes in reader::push_decl_to_scope
reader: Fix building of reference type
abidw: Make generic options like --verbose work with the ABIXML front-end
ir: Improve legibility of set_member_function_is_virtual
ir: Don't cache internal name of non-canonicalized function types
reader: Avoid empty return type node for a function type IR
ir: Handle ptr to fn type member with empty void return type
ctf-reader: Enumerate dicts in the archive rather than using their name
dwarf-reader: Better support concrete instance functions DIEs
btf-reader: Add logging methods
dwarf-reader: Fix support of suppression specifications
ctf-reader: Make logging more obvious
dwarf-reader: Do not fix ELF symbols for virtual destructors
abipkgdiff: Make --verbose enable the library's logging
Implement type hashing
ir: Remove the now useless type propagation optimization
ir: decl-only classes don't equal fully defined classes under ODR
comp-filter: Consider lvalue-ness changes on references as harmful
comp-filter: Ignore ptr size when detecting void ptr to ptr change
Don't strip typedefs in fn names when pretty-printing and comparing
reader: Avoid duplicating member types
ir: Cache the result of scope_decl::get_sorted_member_types
dwarf-reader: Avoid duplicating anonymous member types
reader: Avoid duplicating recursive types
dwarf-reader: Speed-up decl-only resolution
ir: Fix name setting of a ptr-to-mbr-type
dwarf-reader: Support LLVM's lingo of declaration-ness
reader: Improve logging in the ABIXML reader
ir: Improve type logging during type canonicalization
tools-utils: Improve logging while reading a Linux kernel
dwarf-reader: Fix building of void, void* and variadic parm types
{dwarf,btf,ctf}-reader: Set the origin of the corpus group
{btf,ctf,dwarf}-reader, ir: Fix self-comparison debugging for corpus groups
abilint: Support --verbose option
big-tests: Update git sub-module
dwarf-reader,tools-utils: Add statistics about built/suppressed functions
abidw: Add a --kmi-stablelist option alongside existing --kmi-whitelist
dwarf-reader,ir: Fix endless loop while analyzing DWARF from Modula-2
abipkgdiff: Extract devel and main packages in the same directory
dwarf-reader,reader.cc: Fix function virtuality setting
dwarf-reader,ir,writer: Better support for static member variables
comparison: Sort anonymous types using their flat representation
hash,reader,writer: (De)Serialize hash values using the xxhash canonical form
ir: Strip typedefs from pointed-to-types during comparison
ir: Improve the checks done by 'abidw --debug-tc'
ABIXML reader: Unconditionally map a pointer XML node to its decl
corpus: Allow several variables with same ID to be exported
ir: Use definition of decl-only parm type in function type names
big-tests: Update to commit bd0c1f8909a7b2f5018d54b82f7d6829c4849b59
ir: Always use canonical types in comparison when possible
ir: Don't strip typedefs when comparing pointers & references
big-tests: Update to latest version of libabigail-tests.git
reader: Drop the hash values coming from older ABIXML files
hash: Implement full recursive hashing of artifacts
writer: Do not crash on ABI corpora that have no associated path
hash: Use the faster XXH3 hashing algorithm from xxhash
writer: Fix emitting of some member types within their scope
ir: Use canonical types in comparison when --enable-debug-type-canonicalization
big-tests: Update to commit cc6747bb859f6a4d7a3e2198d65618aa5d718fc1
configure: Bump LIBABIGAIL_SO_CURRENT version to 5
ChangeLog: Update ChangeLog in preparation for 2.6 release
Frank Ch. Eigler (1):
configure,abidb: Make the libarchive python module optional for abidb
Mark Wielaard (1):
Use XXH_INLINE_ALL=1 to inline all xxhash functions
Romain Geissler (1):
leaf-reporter: Fix build with gcc 4.9.
Ross Burton (1):
configure.ac: improve fts checks
Sam James (1):
tests/runtestabidb?.sh.in: Use bash shebang
2.5
===
Dodji Seketeli (55):
configure: Bump development version to 2.5
Bug 31045 - Don't try setting translation unit for unique types
suppression: Add "has_strict_flexible_array_data_member_conversion" property
abilint: Support --annotate
abilint: Alphabetically sort programs options
Improve type naming
Bug 30260 - Support pointer-to-member type
Bump abixml version to 2.3
Bump LIBABIGAIL_SO_CURRENT version to 4
Bug 31236 - Fix removing a member declaration from its scope
Bug 31279 - Acknowledge that opaque types are always decl-only
Remove python3-mock dependency and use unittest.mock instead
abidw: Fix indentation
ir: Fix wording of several comments
ir: Avoid duplicates when reading member functions
dwarf-reader: Avoid duplicating union members
dwarf-reader: Fix detection of C language DIEs
writer: Avoid emitting a canonical type twice
writer: Don't forget data members when emitting referenced types
ir: Introduce a missing IR kind for subrange types
ir: Cache internal name for several types
dwarf-reader,corpus: Use interned string to lookup corpus interfaces by ID.
dwarf-reader: Bug 31377 - Fix the IR for zero length arrays
PR25409-librte_bus_dpaa.so.20.0.abi: Update to 2.3
btr-reader: Fix wording typo
ir,{btf,ctf,dwarf}-reader: Rename {subrange_type,array_type_def}::is_infinite.
test-alt-dwarf-file.cc: Fix test result accounting
test-abicomat.cc: Don't show details about PASSing tests.
ir: Fix indentation
ir,corpus,comparison: Const-iffy the access to corpus interfaces
abicompat: Port this to the multi-front-end architecture
ir: Use linkage name to sort virtual function members
dwarf-reader, ir: Add member fns to exported corpus fns after c14n
dwarf-reader: Fix DIE origin handling & scope getting
tests/data/test-diff-pkg: Update dpkg related reference output
ir,dwarf-reader: Better handle inline-ness setting or detection
comparison: Better sort function difference report
ir,dwarf-reader: Peel const-qualifier from const this pointers
dwarf-reader: Support creating functions from DW_TAG_inlined_subroutine
abidw: Add a -o short option for --out-file
tools-utils.cc: Fix potential crash when testing for CTF debug info
Represent undefined corpus interfaces to analyze app compatibility
Factorize elf-reader::{variable,function}_symbol_is_exported into symtab
Add support for undefined symbols in the BTF reader
Emit & read undefined interfaces to & from ABIXML
abicompat: Fix exit code in weak mode
ir: Fix Emacs C++ mode header
comparison: Fix typo
suppression: Fix indentation
abidiff: Fix indentation of help string
Bug 31513 - abidiff considers data members moved to base class as harmful
comparison: Fix erroneous detection of deleted anonymous data members
Bug 31513 - Fix fallout of initial patch
Bug 29160 - support fn symbol aliasing a var symbol
Bug 31646: Fix type suppression tactics for webkit2gtk3
tests/runtestabidb?.sh.in: Fix git initialization
configure: Add option to disable abidb
Frank Ch. Eigler (2):
abidb: Introduce a tool to manage the ABI of a Linux distribution
abidb: drop the TODO items from the python script
Giuliano Procida (1):
website: doxygen: set PROJECT_NAME to libabigail
Mark Wielaard (2):
Fix ABG_ASSERT in build_ir_node_from_die for DW_TAG_member
Recognize EM_RISCV in e_machine_to_string
2.4
===
Dmitry V. Levin (1):
+1 -1
View File
@@ -3,7 +3,7 @@
"Name": "libabigail",
"License": "Apache License 2.0",
"License File": "LICENSE.txt",
"Version Number": "2.4",
"Version Number": "2.8",
"Owner": "zhanghaibo0@huawei.com",
"Upstream URL": "https://sourceware.org/libabigail/",
"Description": "ABI check for dynamic libraries of different versions."
+34
View File
@@ -0,0 +1,34 @@
The libabigail library and utilities aim to be generally robust and
reliable. However, libabigail routinely processes complex binary
structured data. This makes the code intricate and sometimes brittle.
While libabigail developers use a variety of static and dynamic checker
software (valgrind, sanitizers) in testing, bugs may remain. Some of
these bugs may have security-related implications.
While many errors are cleanly detected at runtime, it is possible that
vulnerabilities exist that could be exploitable. These may arise from
crafted / fuzzed / erroneous inputs, or perhaps even from valid inputs
with unforseen characteristics. Therefore, to minimize risks, users
of libabigail tools and libraries should consider measures such as:
- avoiding running complex libabigail analysis on untrustworthy inputs
- avoiding running libabigail tools as privileged processes
- applying common platform level protection mechanisms such as
selinux, syscall filtering, hardened compilation, etc.
Since libabigail tools are usually run in short-lived, local,
interactive, development context rather than remotely "in production",
we generally treat malfunctions as ordinary bugs rather than security
vulnerabilities.
Please report bugs via any of:
- email to <libabigail@sourceware.org>
- https://sourceware.org/bugzilla/enter_bug.cgi?product=libabigail
After considering the above exclusions, please report suspected
security vulnerabilities confidentially via any of:
- email to <dodji@seketeli.org>
- email to <fche@elastic.org>
- email to <secalert@redhat.com>
+107 -13
View File
@@ -29,9 +29,27 @@
/* Define to 1 if dwarf.h has the DW_FORM_strx4 enumerator */
#define HAVE_DW_FORM_strx4 1
/* Define to 1 if dwarf.h has the DW_LANG_Ada2005 enumerator */
#define HAVE_DW_LANG_Ada2005_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Ada2012 enumerator */
#define HAVE_DW_LANG_Ada2012_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Assembly enumerator */
#define HAVE_DW_LANG_Assembly_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_C11 enumerator */
#define HAVE_DW_LANG_C11_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_C17 enumerator */
#define HAVE_DW_LANG_C17_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_C23 enumerator */
#define HAVE_DW_LANG_C23_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_CPP_for_OpenCL enumerator */
#define HAVE_DW_LANG_CPP_for_OpenCL_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_C_plus_plus_03 enumerator */
#define HAVE_DW_LANG_C_plus_plus_03_enumerator 1
@@ -41,27 +59,99 @@
/* Define to 1 if dwarf.h has the DW_LANG_C_plus_plus_14 enumerator */
#define HAVE_DW_LANG_C_plus_plus_14_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_C_plus_plus_17 enumerator */
#define HAVE_DW_LANG_C_plus_plus_17_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_C_plus_plus_20 enumerator */
#define HAVE_DW_LANG_C_plus_plus_20_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_C_plus_plus_23 enumerator */
#define HAVE_DW_LANG_C_plus_plus_23_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_C_sharp enumerator */
#define HAVE_DW_LANG_C_sharp_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Crystal enumerator */
#define HAVE_DW_LANG_Crystal_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_D enumerator */
#define HAVE_DW_LANG_D_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Fortran18 enumerator */
#define HAVE_DW_LANG_Fortran18_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Fortran23 enumerator */
#define HAVE_DW_LANG_Fortran23_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_GLSL_ES enumerator */
#define HAVE_DW_LANG_GLSL_ES_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_GLSL enumerator */
#define HAVE_DW_LANG_GLSL_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Go enumerator */
#define HAVE_DW_LANG_Go_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_HIP enumerator */
#define HAVE_DW_LANG_HIP_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_HLSL enumerator */
#define HAVE_DW_LANG_HLSL_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Hylo enumerator */
#define HAVE_DW_LANG_Hylo_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Kotlin enumerator */
#define HAVE_DW_LANG_Kotlin_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Metal enumerator */
#define HAVE_DW_LANG_Metal_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Mips_Assembler enumerator */
#define HAVE_DW_LANG_Mips_Assembler_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Mojo enumerator */
#define HAVE_DW_LANG_Mojo_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Move enumerator */
#define HAVE_DW_LANG_Move_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_OCaml enumerator */
#define HAVE_DW_LANG_OCaml_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Odin enumerator */
#define HAVE_DW_LANG_Odin_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_OpenCL_CPP enumerator */
#define HAVE_DW_LANG_OpenCL_CPP_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_P4 enumerator */
#define HAVE_DW_LANG_P4_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Python enumerator */
#define HAVE_DW_LANG_Python_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Ruby enumerator */
#define HAVE_DW_LANG_Ruby_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Rust enumerator */
#define HAVE_DW_LANG_Rust_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_SYCL enumerator */
#define HAVE_DW_LANG_SYCL_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_UPC enumerator */
#define HAVE_DW_LANG_UPC_enumerator 1
/* Define to 1 if dwarf.h has the DW_LANG_Zig enumerator */
#define HAVE_DW_LANG_Zig_enumerator 1
/* Defined to 1 if elf.h has EM_AARCH64 macro defined */
#define HAVE_EM_AARCH64_MACRO 1
/* Defined to 1 if elf.h has EM_RISCV macro defined */
#define HAVE_EM_RISCV_MACRO 1
/* Defined to 1 if elf.h has EM_TILEGX macro defined */
#define HAVE_EM_TILEGX_MACRO 1
@@ -107,9 +197,6 @@
/* Define to 1 if you have the <wchar.h> header file. */
#define HAVE_WCHAR_H 1
/* Defined if libdw has the function dwarf_getalt */
#define LIBDW_HAS_DWARF_GETALT 1
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#define LT_OBJDIR ".libs/"
@@ -126,7 +213,7 @@
#define PACKAGE_NAME "libabigail"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "libabigail 2.4"
#define PACKAGE_STRING "libabigail 2.8"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libabigail"
@@ -135,14 +222,14 @@
#define PACKAGE_URL "http://sourceware.org/libabigail"
/* Define to the version of this package. */
#define PACKAGE_VERSION "2.4"
#define PACKAGE_VERSION "2.8"
/* Define to 1 if all of the C90 standard headers exist (not just the ones
/* Define to 1 if all of the C89 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
#define STDC_HEADERS 1
/* Enable extensions on AIX 3, Interix. */
/* Enable extensions on AIX, Interix, z/OS. */
#ifndef _ALL_SOURCE
# define _ALL_SOURCE 1
#endif
@@ -203,11 +290,15 @@
#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
# define __STDC_WANT_IEC_60559_DFP_EXT__ 1
#endif
/* Enable extensions specified by C23 Annex F. */
#ifndef __STDC_WANT_IEC_60559_EXT__
# define __STDC_WANT_IEC_60559_EXT__ 1
#endif
/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1
#endif
/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */
/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
#endif
@@ -231,7 +322,7 @@
/* Version number of package */
#define VERSION "2.4"
#define VERSION "2.8"
/* The BTF_KIND_DECL_TAG enumerator is present */
/* #undef WITH_BTF_KIND_DECL_TAG */
@@ -248,9 +339,6 @@
/* compile the deb package support in abipkgdiff */
#define WITH_DEB 1
/* compile support of debugging canonical type propagation */
/* #undef WITH_DEBUG_CT_PROPAGATION */
/* compile support of debugging abidw --abidiff */
/* #undef WITH_DEBUG_SELF_COMPARISON */
@@ -276,5 +364,11 @@
/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */
/* Define for large files, on AIX-style hosts. */
/* Define to 1 on platforms where this makes off_t a 64-bit type. */
/* #undef _LARGE_FILES */
/* Number of bits in time_t, on hosts where this is settable. */
/* #undef _TIME_BITS */
/* Define to 1 on platforms where this makes time_t a 64-bit type. */
/* #undef __MINGW_USE_VC2005_COMPAT */
+104 -10
View File
@@ -28,9 +28,27 @@
/* Define to 1 if dwarf.h has the DW_FORM_strx4 enumerator */
#undef HAVE_DW_FORM_strx4
/* Define to 1 if dwarf.h has the DW_LANG_Ada2005 enumerator */
#undef HAVE_DW_LANG_Ada2005_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Ada2012 enumerator */
#undef HAVE_DW_LANG_Ada2012_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Assembly enumerator */
#undef HAVE_DW_LANG_Assembly_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_C11 enumerator */
#undef HAVE_DW_LANG_C11_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_C17 enumerator */
#undef HAVE_DW_LANG_C17_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_C23 enumerator */
#undef HAVE_DW_LANG_C23_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_CPP_for_OpenCL enumerator */
#undef HAVE_DW_LANG_CPP_for_OpenCL_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_C_plus_plus_03 enumerator */
#undef HAVE_DW_LANG_C_plus_plus_03_enumerator
@@ -40,27 +58,99 @@
/* Define to 1 if dwarf.h has the DW_LANG_C_plus_plus_14 enumerator */
#undef HAVE_DW_LANG_C_plus_plus_14_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_C_plus_plus_17 enumerator */
#undef HAVE_DW_LANG_C_plus_plus_17_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_C_plus_plus_20 enumerator */
#undef HAVE_DW_LANG_C_plus_plus_20_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_C_plus_plus_23 enumerator */
#undef HAVE_DW_LANG_C_plus_plus_23_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_C_sharp enumerator */
#undef HAVE_DW_LANG_C_sharp_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Crystal enumerator */
#undef HAVE_DW_LANG_Crystal_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_D enumerator */
#undef HAVE_DW_LANG_D_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Fortran18 enumerator */
#undef HAVE_DW_LANG_Fortran18_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Fortran23 enumerator */
#undef HAVE_DW_LANG_Fortran23_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_GLSL_ES enumerator */
#undef HAVE_DW_LANG_GLSL_ES_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_GLSL enumerator */
#undef HAVE_DW_LANG_GLSL_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Go enumerator */
#undef HAVE_DW_LANG_Go_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_HIP enumerator */
#undef HAVE_DW_LANG_HIP_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_HLSL enumerator */
#undef HAVE_DW_LANG_HLSL_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Hylo enumerator */
#undef HAVE_DW_LANG_Hylo_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Kotlin enumerator */
#undef HAVE_DW_LANG_Kotlin_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Metal enumerator */
#undef HAVE_DW_LANG_Metal_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Mips_Assembler enumerator */
#undef HAVE_DW_LANG_Mips_Assembler_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Mojo enumerator */
#undef HAVE_DW_LANG_Mojo_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Move enumerator */
#undef HAVE_DW_LANG_Move_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_OCaml enumerator */
#undef HAVE_DW_LANG_OCaml_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Odin enumerator */
#undef HAVE_DW_LANG_Odin_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_OpenCL_CPP enumerator */
#undef HAVE_DW_LANG_OpenCL_CPP_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_P4 enumerator */
#undef HAVE_DW_LANG_P4_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Python enumerator */
#undef HAVE_DW_LANG_Python_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Ruby enumerator */
#undef HAVE_DW_LANG_Ruby_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Rust enumerator */
#undef HAVE_DW_LANG_Rust_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_SYCL enumerator */
#undef HAVE_DW_LANG_SYCL_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_UPC enumerator */
#undef HAVE_DW_LANG_UPC_enumerator
/* Define to 1 if dwarf.h has the DW_LANG_Zig enumerator */
#undef HAVE_DW_LANG_Zig_enumerator
/* Defined to 1 if elf.h has EM_AARCH64 macro defined */
#undef HAVE_EM_AARCH64_MACRO
/* Defined to 1 if elf.h has EM_RISCV macro defined */
#undef HAVE_EM_RISCV_MACRO
/* Defined to 1 if elf.h has EM_TILEGX macro defined */
#undef HAVE_EM_TILEGX_MACRO
@@ -106,9 +196,6 @@
/* Define to 1 if you have the <wchar.h> header file. */
#undef HAVE_WCHAR_H
/* Defined if libdw has the function dwarf_getalt */
#undef LIBDW_HAS_DWARF_GETALT
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#undef LT_OBJDIR
@@ -136,12 +223,12 @@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 if all of the C90 standard headers exist (not just the ones
/* Define to 1 if all of the C89 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
#undef STDC_HEADERS
/* Enable extensions on AIX 3, Interix. */
/* Enable extensions on AIX, Interix, z/OS. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
@@ -202,11 +289,15 @@
#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
# undef __STDC_WANT_IEC_60559_DFP_EXT__
#endif
/* Enable extensions specified by C23 Annex F. */
#ifndef __STDC_WANT_IEC_60559_EXT__
# undef __STDC_WANT_IEC_60559_EXT__
#endif
/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
# undef __STDC_WANT_IEC_60559_FUNCS_EXT__
#endif
/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */
/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
# undef __STDC_WANT_IEC_60559_TYPES_EXT__
#endif
@@ -256,9 +347,6 @@
/* compile the deb package support in abipkgdiff */
#undef WITH_DEB
/* compile support of debugging canonical type propagation */
#undef WITH_DEBUG_CT_PROPAGATION
/* compile support of debugging abidw --abidiff */
#undef WITH_DEBUG_SELF_COMPARISON
@@ -284,5 +372,11 @@
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Define for large files, on AIX-style hosts. */
/* Define to 1 on platforms where this makes off_t a 64-bit type. */
#undef _LARGE_FILES
/* Number of bits in time_t, on hosts where this is settable. */
#undef _TIME_BITS
/* Define to 1 on platforms where this makes time_t a 64-bit type. */
#undef __MINGW_USE_VC2005_COMPAT
+541 -64
View File
@@ -1,9 +1,18 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
dnl SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
dnl Process this file with autoconf to produce a configure script.
dnl Configure input file for Libabigail. -*-autoconf-*-
dnl
dnl Copyright (C) 2013-2025 Red Hat, Inc.
dnl Author: Dodji Seketeli
dnl
dnl This file is part of Libabigail.
dnl
dnl Libabigail version number is handled here with the major and minor
dnl version numbers.
m4_define([version_major], [2])
m4_define([version_minor], [4])
m4_define([version_minor], [8])
dnl Below are the numbers to handle libabigail.so's versionning
dnl following the libtool's versionning scheme to handle shared
@@ -25,7 +34,7 @@ dnl then increment LIBABIGAIL_SO_AGE.
dnl
dnl 4. If any interfaces have been removed or changed since the last
dnl public release, then set LIBABIGAIL_SO_AGE to 0.
m4_define([libabigail_so_current], [3])
m4_define([libabigail_so_current], [7])
m4_define([libabigail_so_revision], [0])
m4_define([libabigail_so_age], [0])
@@ -84,7 +93,7 @@ dnl The minor version number of the abixml version should be changed
dnl each time and old version of libabigail can't handle a new version
dnl of abixml. Note however that when the major version number is
dnl changed, the minor version number should be set to zero.
ABIXML_VERSION_MINOR=2
ABIXML_VERSION_MINOR=4
LIBABIGAIL_SO_CURRENT=libabigail_so_current
LIBABIGAIL_SO_REVISION=libabigail_so_revision
LIBABIGAIL_SO_AGE=libabigail_so_age
@@ -134,11 +143,6 @@ AC_ARG_ENABLE(debug-type-canonicalization,
ENABLE_DEBUG_TYPE_CANONICALIZATION=$enableval,
ENABLE_DEBUG_TYPE_CANONICALIZATION=no)
AC_ARG_ENABLE(debug-ct-propagation,
AS_HELP_STRING([--enable-debug-ct-propagation=yes|no],
[enable debugging of canonical type propagation (default is no)]),
ENABLE_DEBUG_CT_PROPAGATION=$enableval,
ENABLE_DEBUG_CT_PROPAGATION=no)
AC_ARG_ENABLE(show-type-use-in-abilint,
AS_HELP_STRING([--enable-show-type-use-in-abilint=yes|no],
@@ -182,6 +186,12 @@ AC_ARG_ENABLE([fedabipkgdiff],
ENABLE_FEDABIPKGDIFF=$enableval,
ENABLE_FEDABIPKGDIFF=auto)
AC_ARG_ENABLE(abidb,
AS_HELP_STRING([--enable-abidb=yes|no|auto],
[enable the support of the abidb tool (default is auto)]),
ENABLE_ABIDB=$enableval,
ENABLE_ABIDB=auto)
AC_ARG_ENABLE([python3],
AS_HELP_STRING([--enable-python3=yes|no|auto],
[enable running abigail tools with python3 (default is auto)]),
@@ -225,6 +235,43 @@ AC_ARG_ENABLE(btf,
[disable support of btf files)]),
ENABLE_BTF=$enableval,
ENABLE_BTF=auto)
ENABLE_BIG_TESTS=no
AC_ARG_ENABLE(big-tests,
AS_HELP_STRING([--enable-big-tests=yes|no],
[enable the support of libabigail big tests (in the big-tests subdir)]),
ENABLE_BIG_TESTS=$enableval,
ENABLE_BIG_TESTS=no)
ENABLE_INLINED_XXHASH=no
AC_ARG_ENABLE(inlined-xxhash,
AS_HELP_STRING([--enable-inlined-xxhash=yes|no],
[enable the support the inlined-only version of the xxhash library]),
ENABLE_INLINED_XXHASH=$enableval,
ENABLE_INLINED_XXHASH=no)
WITH_DW_LIBS_PATH=auto
AC_ARG_WITH(libdw,
AS_HELP_STRING([--with-libdw=/path/to/libdw-library/prefix],
[Set the path to the libdw library prefix]),
WITH_DW_LIBS_PATH=$withval,
WITH_DW_LIBS_PATH=auto)
WITH_ELF_LIBS_PATH=auto
AC_ARG_WITH(libelf,
AS_HELP_STRING([--with-libelf=/path/to/libelf-library/prefix],
[Set the path to the libelf library prefix]),
WITH_ELF_LIBS_PATH=$withval,
WITH_ELF_LIBS_PATH=auto)
WITH_LIBXML2_PATH=auto
AC_ARG_WITH(libxml2,
AS_HELP_STRING([--with-libxml2=/path/to/libxml2-library/prefix],
[Set the path to the libxml2 library prefix]),
WITH_LIBXML2_PATH=$withval,
WITH_LIBXML2_PATH=auto)
dnl *************************************************
dnl check for dependencies
dnl *************************************************
@@ -241,9 +288,11 @@ AC_LANG([C++])
AC_LANG_COMPILER_REQUIRE
dnl
dnl We use C++11
dnl We use C++14. It has been the default in G++ since GCC 6. In el8
dnl (that we still support), we do have GCC 8.x with c++14 as the
dnl default, still.
dnl
CXX_STANDARD=c++11
CXX_STANDARD=c++14
dnl
dnl check if the c++ compiler has support __attribute__((visibility("hidden")))
@@ -275,6 +324,10 @@ fi
AC_SUBST(VISIBILITY_FLAGS)
dnl glibc and BSD include fts into their libc, but musl does not so
dnl check if we need to explicitly link to the standalone musl-fts.
AC_SEARCH_LIBS([fts_open], [fts])
dnl Older glibc had a broken fts that didn't work with Large File Systems.
dnl We want the version that can handler LFS, but include workaround if we
dnl get a bad one. Add define to CFLAGS (not AC_DEFINE it) since we need to
@@ -289,31 +342,38 @@ AS_IF([test "x$ac_cv_bad_fts" = "xyes"],
[CFLAGS="$CFLAGS -DBAD_FTS=1",
CXXFLAGS="$CXXFLAGS -DBAD_FTS=1"])
dnl On musl, we need to find fts-standalone
AS_CASE(
[${host_os}], [*-musl*], [
PKG_CHECK_MODULES([FTS], [fts-standalone])
])
dnl Check for dependency: libelf, libdw, libebl (elfutils)
dnl Note that we need to use at least elfutils 0.159 but
dnl at that time elfutils didnt have pkgconfig capabilities
dnl to easily query for its version.
ELF_LIBS=
AC_CHECK_LIB([elf], [elf_end], [ELF_LIBS="-lelf"])
AC_CHECK_HEADER([libelf.h],
[],
[AC_MSG_ERROR([could not find libelf.h])])
dnl Check for dependency: libelf and libdw (elfutils). Note that we
dnl need to use at least elfutils 0.159 but at that time elfutils
dnl didnt have pkgconfig capabilities to easily query for its version.
dnl Those were added in version 0.165.
DW_LIBS=
AC_CHECK_LIB(dw, dwfl_begin, [DW_LIBS=-ldw])
AC_CHECK_LIB(dw, dwarf_getalt,
[FOUND_DWARF_GETALT_IN_LIBDW=yes],
[FOUND_DWARF_GETALT_IN_LIBDW=no])
dnl look for libelf
ELF_LIBS_VERSION=0.165
SAVED_PKG_CONFIG_PATH=$PKG_CONFIG_PATH
if test $WITH_ELF_LIBS_PATH != xauto; then
export PKG_CONFIG_PATH="$WITH_ELF_LIBS_PATH/lib/pkgconfig:$PKG_CONFIG_PATH"
fi
AC_MSG_NOTICE([used PKG_CONFIG_PATH=$PKG_CONFIG_PATH to check for libelf]);
PKG_CHECK_MODULES(ELF, libelf >= $ELF_LIBS_VERSION)
if test $WITH_ELF_LIBS_PATH != xauto; then
PKG_CONFIG_PATH=$SAVED_PKG_CONFIG_PATH
fi
dnl Look for libdw
DW_LIBS_VERSION=0.165
SAVED_PKG_CONFIG_PATH=$PKG_CONFIG_PATH
if test $WITH_DW_LIBS_PATH != xauto; then
export PKG_CONFIG_PATH="$WITH_DW_LIBS_PATH/lib/pkgconfig:$PKG_CONFIG_PATH"
fi
AC_MSG_NOTICE([used PKG_CONFIG_PATH=$PKG_CONFIG_PATH to check for libdw]);
PKG_CHECK_MODULES(DW, libdw >= $DW_LIBS_VERSION)
if test $WITH_DW_LIBS_PATH != xauto; then
PKG_CONFIG_PATH=$SAVED_PKG_CONFIG_PATH
fi
AC_CHECK_HEADER(elfutils/libdwfl.h,
[],
[AC_MSG_ERROR([could not find elfutils/libdwfl.h installed])])
dnl Allow users to compile with the NDEBUG macro defined,
dnl meaning they are compiling in a mode where the
@@ -322,21 +382,10 @@ dnl users just need to pass the --disable-assert
dnl option to configure.
AC_HEADER_ASSERT
if test x$ELF_LIBS = x; then
AC_MSG_ERROR([could not find elfutils elf library installed])
fi
if test x$DW_LIBS = x; then
AC_MSG_ERROR([could not find elfutils dwarf library installed])
fi
if test x$FOUND_DWARF_GETALT_IN_LIBDW = xyes; then
AC_DEFINE([LIBDW_HAS_DWARF_GETALT], 1,
[Defined if libdw has the function dwarf_getalt])
fi
AC_SUBST(DW_LIBS)
AC_SUBST(DW_CFLAGS)
AC_SUBST([ELF_LIBS])
AC_SUBST([ELF_CFLAGS])
dnl check for libctf presence if CTF code has been enabled by command line
dnl argument, and then define CTF flag (to build CTF file code) if libctf is
@@ -385,10 +434,10 @@ dnl configure BTF usage
BPF_LIBS=
if test x$ENABLE_BTF != xno; then
AC_CHECK_HEADER([bpf/btf.h],
[ENABLE_BTF=yes],
[HAS_BTF_HEADERS=yes],
[AC_MSG_NOTICE([could not find bpf/btf.h])])
if test x$ENABLE_BTF = xyes; then
AC_MSG_NOTICE([enable BTF support])
if test x$HAS_BTF_HEADERS = xyes; then
AC_MSG_NOTICE([found BTF header file so enabling BTF support])
ENABLE_BTF=yes
AC_DEFINE([WITH_BTF], 1,
[Defined if user enabled BTF usage])
@@ -452,14 +501,58 @@ dnl Test if various functions and structs are present.
fi
fi
if test x$ENABLE_BIG_TESTS = xyes; then
AC_MSG_NOTICE([looking for $srcdir/big-tests ...]);
if test -d $srcdir/big-tests -o -L $srcdir/big-tests; then
AC_CONFIG_COMMANDS([create-big-tests-build-dir-and-configure],
[AC_MSG_NOTICE([Found $srcdir/big-tests!])
cd $ac_abs_top_srcdir/big-tests
autoreconf -i
cd $ac_abs_top_builddir
test -d big-tests || mkdir big-tests
cd big-tests
CTF_OPTS=
BTF_OPTS=
if test x$CTF_ENABLED = xyes; then CTF_OPTS="--enable-ctf"; fi;
if test x$BTF_ENABLED = xyes; then BTF_OPTS="--enable-btf"; fi;
AC_MSG_NOTICE([configuring $srcdir/big-tests --with-libabigail-tools-dir=$ac_abs_top_builddir/tools --with-libabigail-headers-dir=$ac_abs_top_srcdir/include $CTF_OPTS $BTF_OPTS])
$ac_abs_top_srcdir/big-tests/configure --with-libabigail-tools-dir=$ac_abs_top_builddir/tools --with-libabigail-headers-dir=$ac_abs_top_srcdir/include $CTF_OPTS $BTF_OPTS],
[CTF_ENABLED=$ENABLE_CTF
BTF_ENABLED=$ENABLE_BTF])
else
AC_MSG_ERROR([No sub-directory big-tests found. Please checkout libabigail-big-tests under a sub-directory named 'big-tests'])
fi
fi
dnl Check for dependency: libxml
LIBXML2_VERSION=2.6.22
SAVED_PKG_CONFIG_PATH=$PKG_CONFIG_PATH
if test $WITH_LIBXML2_PATH != xauto; then
export PKG_CONFIG_PATH="$WITH_LIBXML2_PATH/lib/pkgconfig:$PKG_CONFIG_PATH"
fi
AC_MSG_NOTICE([used PKG_CONFIG_PATH=$PKG_CONFIG_PATH to check for libxml2]);
PKG_CHECK_MODULES(XML, libxml-2.0 >= $LIBXML2_VERSION)
if test $WITH_LIBXML2_PATH != xauto; then
PKG_CONFIG_PATH=$SAVED_PKG_CONFIG_PATH
fi
AC_SUBST(LIBXML2_VERSION)
AC_SUBST(XML_LIBS)
AC_SUBST(XML_CFLAGS)
dnl Check for dependency: xxhash
XXHASH_VERSION=0.8.0
PKG_CHECK_MODULES(XXHASH, libxxhash >= $XXHASH_VERSION)
AC_SUBST(XXHASH_CFLAGS)
AC_SUBST(XXHASH_LIBS)
dnl Check for dependency: liblzma
LIBLZMA_VERSION=5.2.0
PKG_CHECK_MODULES(LZMA, liblzma >= $LIBLZMA_VERSION)
AC_SUBST(LZMA_CFLAGS)
AC_SUBST(LZMA_LIBS)
dnl Check for some programs like rm, mkdir, etc ...
AC_CHECK_PROG(HAS_RM, rm, yes, no)
if test x$HAS_RM = xno; then
@@ -567,15 +660,6 @@ fi
AM_CONDITIONAL(ENABLE_DEBUG_TYPE_CANONICALIZATION, test x$ENABLE_DEBUG_TYPE_CANONICALIZATION = xyes)
if test x$ENABLE_DEBUG_CT_PROPAGATION = xyes; then
AC_DEFINE([WITH_DEBUG_CT_PROPAGATION],
1,
[compile support of debugging canonical type propagation])
AC_MSG_NOTICE([support of debugging canonical type propagation is enabled])
else
AC_MSG_NOTICE([support of debugging canonical type propagation is disabled])
fi
dnl Check for the dpkg program
if test x$ENABLE_DEB = xauto -o x$ENABLE_DEB = xyes; then
AC_CHECK_PROG(HAS_DPKG, dpkg, yes, no)
@@ -764,7 +848,7 @@ if test x$CHECK_DEPS_FOR_FEDABIPKGDIFF = xyes; then
REQUIRED_PYTHON_MODULES_FOR_FEDABIPKGDIFF="\
argparse logging os re subprocess sys $URLPARSE_MODULE \
xdg koji mock rpm $IMPORT_MODULE tempfile mimetypes shutil six"
xdg koji rpm $IMPORT_MODULE tempfile mimetypes shutil six"
AX_CHECK_PYTHON_MODULES([$REQUIRED_PYTHON_MODULES_FOR_FEDABIPKGDIFF],
[$PYTHON],
@@ -816,12 +900,52 @@ except koji.ConfigurationError:
fi
fi
dnl abidb checks
if test x$PYTHON3_INTERPRETER != xno -a x$ENABLE_ABIDB != xno; then
AX_CHECK_PYTHON_MODULES([git],
[$PYTHON],
[FOUND_ALL_PYTHON_MODULES=yes],
[FOUND_ALL_PYTHON_MODULES=no])
$PYTHON3_INTERPRETER -c "import sys; sys.exit(0 if sys.version_info >= (3, 9) else 1)"
if test $? -ne 0; then
AC_MSG_NOTICE([Python 3 version 3.9 or higher is required for abidb])
AC_MSG_WARN([disabling abidb as a result])
ENABLE_ABIDB=no
else
AC_MSG_NOTICE([Found Python 3 version at 3.9 or higher. Great for abidb!])
fi
if test x$ENABLE_ABIDB = xno; then
pass
elif test x$ENABLE_ABIDB != xno -a x$FOUND_ALL_PYTHON_MODULES = xno; then
AC_MSG_NOTICE([missing python modules: $MISSING_PYTHON_MODULES])
AC_MSG_WARN([disabling abidb as a result])
ENABLE_ABIDB=no
else
ENABLE_ABIDB=yes
dnl search for optional modules, just for autoconf reporting purposes
AX_CHECK_PYTHON_MODULES([libarchive],
[$PYTHON],
[FOUND_ALL_OPTIONAL_PYTHON_MODULES=yes],
[FOUND_ALL_OPTIONAL_PYTHON_MODULES=no])
if test x$FOUND_ALL_OPTIONAL_PYTHON_MODULES = xno; then
AC_MSG_WARN([missing optional python modules for abidb: $MISSING_PYTHON_MODULES])
else
AC_MSG_NOTICE([found all optional python modules for abidb])
fi
fi
else
AC_MSG_NOTICE([disabling abidb])
fi
AM_CONDITIONAL(ENABLE_ABIDB, test x$ENABLE_ABIDB = xyes)
AM_CONDITIONAL(ENABLE_FEDABIPKGDIFF, test x$ENABLE_FEDABIPKGDIFF = xyes)
AM_CONDITIONAL(ENABLE_RUNNING_TESTS_WITH_PY3, test x$RUN_TESTS_WITH_PY3 = xyes)
AM_CONDITIONAL(ENABLE_PYTHON3_INTERPRETER, test x$PYTHON3_INTERPRETER != xno)
AC_SUBST(PYTHON)
DEPS_CPPFLAGS="$XML_CFLAGS"
DEPS_CPPFLAGS="$XML_CFLAGS $XXHASH_CFLAGS $ELF_CFLAGS $DW_CFLAGS $LZMA_CFLAGS"
AC_SUBST(DEPS_CPPFLAGS)
dnl Check for the presence of doxygen program
@@ -862,8 +986,10 @@ AX_VALGRIND_DFLT(sgcheck, off)
AX_VALGRIND_CHECK
dnl Set the list of libraries libabigail depends on
DEPS_LIBS="$XML_LIBS $ELF_LIBS $DW_LIBS $CTF_LIBS $BPF_LIBS"
DEPS_LIBS="$XML_LIBS $ELF_LIBS $DW_LIBS $CTF_LIBS $BPF_LIBS $LZMA_LIBS"
if test x$ENABLE_INLINED_XXHASH = xno; then
DEPS_LIBS="$DEPS_LIBS $XXHASH_LIBS"
fi
AC_SUBST(DEPS_LIBS)
if test x$ABIGAIL_DEVEL != x; then
@@ -901,6 +1027,12 @@ if test x$ENABLE_UBSAN = xyes; then
CXXFLAGS="$CXXFLAGS -fsanitize=undefined"
fi
dnl If the user asked then let's use inlined xxhash functions.
if test x$ENABLE_INLINED_XXHASH = xyes; then
CFLAGS="$CFLAGS -DXXH_INLINE_ALL=1"
CXXFLAGS="$CXXFLAGS -DXXH_INLINE_ALL=1"
fi
dnl Set a few Automake conditionals
AM_CONDITIONAL([CTF_READER],[test "x$ENABLE_CTF" = "xyes"])
@@ -947,6 +1079,18 @@ if test x$HAS_EM_TILEGX = xyes; then
[Defined to 1 if elf.h has EM_TILEGX macro defined])
fi
HAS_EM_RISCV=no
AC_CHECK_DECL([EM_RISCV],
[HAS_EM_RISCV=yes],
[HAS_EM_RISCV=no],
[[#include <elf.h>]])
if test x$HAS_EM_RISCV = xyes; then
AC_DEFINE([HAVE_EM_RISCV_MACRO],
1,
[Defined to 1 if elf.h has EM_RISCV macro defined])
fi
HAS_R_AARCH64_ABS64=no
AC_CHECK_DECL([R_AARCH64_ABS64],
[HAS_R_AARCH64_ABS64=yes],
@@ -1082,6 +1226,327 @@ if test x$HAS_DW_LANG_Rust = xyes; then
[Define to 1 if dwarf.h has the DW_LANG_Rust enumerator])
fi
HAS_DW_LANG_OCaml=no
AC_CHECK_DECL([DW_LANG_OCaml],
[HAS_DW_LANG_OCaml=yes],
[HAS_DW_LANG_OCaml=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_OCaml = xyes; then
AC_DEFINE([HAVE_DW_LANG_OCaml_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_OCaml enumerator])
fi
HAS_DW_LANG_Kotlin=no
AC_CHECK_DECL([DW_LANG_Kotlin],
[HAS_DW_LANG_Kotlin=yes],
[HAS_DW_LANG_Kotlin=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_Kotlin = xyes; then
AC_DEFINE([HAVE_DW_LANG_Kotlin_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_Kotlin enumerator])
fi
HAS_DW_LANG_Zig=no
AC_CHECK_DECL([DW_LANG_Zig],
[HAS_DW_LANG_Zig=yes],
[HAS_DW_LANG_Zig=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_Zig = xyes; then
AC_DEFINE([HAVE_DW_LANG_Zig_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_Zig enumerator])
fi
HAS_DW_LANG_Crystal=no
AC_CHECK_DECL([DW_LANG_Crystal],
[HAS_DW_LANG_Crystal=yes],
[HAS_DW_LANG_Crystal=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_Crystal = xyes; then
AC_DEFINE([HAVE_DW_LANG_Crystal_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_Crystal enumerator])
fi
HAS_DW_LANG_C_plus_plus_17=no
AC_CHECK_DECL([DW_LANG_C_plus_plus_17],
[HAS_DW_LANG_C_plus_plus_17=yes],
[HAS_DW_LANG_C_plus_plus_17=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_C_plus_plus_17 = xyes; then
AC_DEFINE([HAVE_DW_LANG_C_plus_plus_17_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_C_plus_plus_17 enumerator])
fi
HAS_DW_LANG_C_plus_plus_20=no
AC_CHECK_DECL([DW_LANG_C_plus_plus_20],
[HAS_DW_LANG_C_plus_plus_20=yes],
[HAS_DW_LANG_C_plus_plus_20=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_C_plus_plus_20 = xyes; then
AC_DEFINE([HAVE_DW_LANG_C_plus_plus_20_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_C_plus_plus_20 enumerator])
fi
HAS_DW_LANG_C17=no
AC_CHECK_DECL([DW_LANG_C17],
[HAS_DW_LANG_C17=yes],
[HAS_DW_LANG_C17=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_C17 = xyes; then
AC_DEFINE([HAVE_DW_LANG_C17_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_C17 enumerator])
fi
HAS_DW_LANG_Fortran18=no
AC_CHECK_DECL([DW_LANG_Fortran18],
[HAS_DW_LANG_Fortran18=yes],
[HAS_DW_LANG_Fortran18=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_Fortran18 = xyes; then
AC_DEFINE([HAVE_DW_LANG_Fortran18_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_Fortran18 enumerator])
fi
HAS_DW_LANG_Ada2005=no
AC_CHECK_DECL([DW_LANG_Ada2005],
[HAS_DW_LANG_Ada2005=yes],
[HAS_DW_LANG_Ada2005=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_Ada2005 = xyes; then
AC_DEFINE([HAVE_DW_LANG_Ada2005_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_Ada2005 enumerator])
fi
HAS_DW_LANG_Ada2012=no
AC_CHECK_DECL([DW_LANG_Ada2012],
[HAS_DW_LANG_Ada2012=yes],
[HAS_DW_LANG_Ada2012=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_Ada2012 = xyes; then
AC_DEFINE([HAVE_DW_LANG_Ada2012_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_Ada2012 enumerator])
fi
HAS_DW_LANG_HIP=no
AC_CHECK_DECL([DW_LANG_HIP],
[HAS_DW_LANG_HIP=yes],
[HAS_DW_LANG_HIP=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_HIP = xyes; then
AC_DEFINE([HAVE_DW_LANG_HIP_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_HIP enumerator])
fi
HAS_DW_LANG_Assembly=no
AC_CHECK_DECL([DW_LANG_Assembly],
[HAS_DW_LANG_Assembly=yes],
[HAS_DW_LANG_Assembly=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_Assembly = xyes; then
AC_DEFINE([HAVE_DW_LANG_Assembly_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_Assembly enumerator])
fi
HAS_DW_LANG_C_sharp=no
AC_CHECK_DECL([DW_LANG_C_sharp],
[HAS_DW_LANG_C_sharp=yes],
[HAS_DW_LANG_C_sharp=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_C_sharp = xyes; then
AC_DEFINE([HAVE_DW_LANG_C_sharp_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_C_sharp enumerator])
fi
HAS_DW_LANG_Mojo=no
AC_CHECK_DECL([DW_LANG_Mojo],
[HAS_DW_LANG_Mojo=yes],
[HAS_DW_LANG_Mojo=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_Mojo = xyes; then
AC_DEFINE([HAVE_DW_LANG_Mojo_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_Mojo enumerator])
fi
HAS_DW_LANG_GLSL=no
AC_CHECK_DECL([DW_LANG_GLSL],
[HAS_DW_LANG_GLSL=yes],
[HAS_DW_LANG_GLSL=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_GLSL = xyes; then
AC_DEFINE([HAVE_DW_LANG_GLSL_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_GLSL enumerator])
fi
HAS_DW_LANG_GLSL_ES=no
AC_CHECK_DECL([DW_LANG_GLSL_ES],
[HAS_DW_LANG_GLSL_ES=yes],
[HAS_DW_LANG_GLSL_ES=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_GLSL_ES = xyes; then
AC_DEFINE([HAVE_DW_LANG_GLSL_ES_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_GLSL_ES enumerator])
fi
HAS_DW_LANG_HLSL=no
AC_CHECK_DECL([DW_LANG_HLSL],
[HAS_DW_LANG_HLSL=yes],
[HAS_DW_LANG_HLSL=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_HLSL = xyes; then
AC_DEFINE([HAVE_DW_LANG_HLSL_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_HLSL enumerator])
fi
HAS_DW_LANG_OpenCL_CPP=no
AC_CHECK_DECL([DW_LANG_OpenCL_CPP],
[HAS_DW_LANG_OpenCL_CPP=yes],
[HAS_DW_LANG_OpenCL_CPP=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_OpenCL_CPP = xyes; then
AC_DEFINE([HAVE_DW_LANG_OpenCL_CPP_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_OpenCL_CPP enumerator])
fi
HAS_DW_LANG_CPP_for_OpenCL=no
AC_CHECK_DECL([DW_LANG_CPP_for_OpenCL],
[HAS_DW_LANG_CPP_for_OpenCL=yes],
[HAS_DW_LANG_CPP_for_OpenCL=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_CPP_for_OpenCL = xyes; then
AC_DEFINE([HAVE_DW_LANG_CPP_for_OpenCL_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_CPP_for_OpenCL enumerator])
fi
HAS_DW_LANG_SYCL=no
AC_CHECK_DECL([DW_LANG_SYCL],
[HAS_DW_LANG_SYCL=yes],
[HAS_DW_LANG_SYCL=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_SYCL = xyes; then
AC_DEFINE([HAVE_DW_LANG_SYCL_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_SYCL enumerator])
fi
HAS_DW_LANG_C_plus_plus_23=no
AC_CHECK_DECL([DW_LANG_C_plus_plus_23],
[HAS_DW_LANG_C_plus_plus_23=yes],
[HAS_DW_LANG_C_plus_plus_23=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_C_plus_plus_23 = xyes; then
AC_DEFINE([HAVE_DW_LANG_C_plus_plus_23_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_C_plus_plus_23 enumerator])
fi
HAS_DW_LANG_Odin=no
AC_CHECK_DECL([DW_LANG_Odin],
[HAS_DW_LANG_Odin=yes],
[HAS_DW_LANG_Odin=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_Odin = xyes; then
AC_DEFINE([HAVE_DW_LANG_Odin_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_Odin enumerator])
fi
HAS_DW_LANG_P4=no
AC_CHECK_DECL([DW_LANG_P4],
[HAS_DW_LANG_P4=yes],
[HAS_DW_LANG_P4=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_P4 = xyes; then
AC_DEFINE([HAVE_DW_LANG_P4_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_P4 enumerator])
fi
HAS_DW_LANG_Metal=no
AC_CHECK_DECL([DW_LANG_Metal],
[HAS_DW_LANG_Metal=yes],
[HAS_DW_LANG_Metal=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_Metal = xyes; then
AC_DEFINE([HAVE_DW_LANG_Metal_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_Metal enumerator])
fi
HAS_DW_LANG_C23=no
AC_CHECK_DECL([DW_LANG_C23],
[HAS_DW_LANG_C23=yes],
[HAS_DW_LANG_C23=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_C23 = xyes; then
AC_DEFINE([HAVE_DW_LANG_C23_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_C23 enumerator])
fi
HAS_DW_LANG_Fortran23=no
AC_CHECK_DECL([DW_LANG_Fortran23],
[HAS_DW_LANG_Fortran23=yes],
[HAS_DW_LANG_Fortran23=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_Fortran23 = xyes; then
AC_DEFINE([HAVE_DW_LANG_Fortran23_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_Fortran23 enumerator])
fi
HAS_DW_LANG_Ruby=no
AC_CHECK_DECL([DW_LANG_Ruby],
[HAS_DW_LANG_Ruby=yes],
[HAS_DW_LANG_Ruby=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_Ruby = xyes; then
AC_DEFINE([HAVE_DW_LANG_Ruby_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_Ruby enumerator])
fi
HAS_DW_LANG_Move=no
AC_CHECK_DECL([DW_LANG_Move],
[HAS_DW_LANG_Move=yes],
[HAS_DW_LANG_Move=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_Move = xyes; then
AC_DEFINE([HAVE_DW_LANG_Move_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_Move enumerator])
fi
HAS_DW_LANG_Hylo=no
AC_CHECK_DECL([DW_LANG_Hylo],
[HAS_DW_LANG_Hylo=yes],
[HAS_DW_LANG_Hylo=no],
[[#include <dwarf.h>]])
if test x$HAS_DW_LANG_Hylo = xyes; then
AC_DEFINE([HAVE_DW_LANG_Hylo_enumerator],
1,
[Define to 1 if dwarf.h has the DW_LANG_Hylo enumerator])
fi
HAS_DW_FORM_strx1=no
HAS_DW_FORM_strx2=no
HAS_DW_FORM_strx3=no
@@ -1182,6 +1647,10 @@ AC_CONFIG_FILES([tests/runtestdefaultsupprs.py],
[chmod +x tests/runtestdefaultsupprs.py])
AC_CONFIG_FILES([tests/runtestdefaultsupprspy3.sh],
[chmod +x tests/runtestdefaultsupprspy3.sh])
AC_CONFIG_FILES([tests/runtestabidb1.sh],
[chmod +x tests/runtestabidb1.sh])
AC_CONFIG_FILES([tests/runtestabidb2.sh],
[chmod +x tests/runtestabidb2.sh])
AC_OUTPUT
@@ -1198,24 +1667,32 @@ AC_MSG_NOTICE([
C++ Compiler : ${CXX}
GCC visibility attribute supported : ${SUPPORTS_GCC_VISIBILITY_ATTRIBUTE}
CXXFLAGS : ${CXXFLAGS}
ELF_LIBS : ${ELF_LIBS}
ELF_CFLAGS : ${ELF_CFLAGS}
DW_LIBS : ${DW_LIBS}
DW_CFLAGS : ${DW_CFLAGS}
XML_LIBS $ ${XML_LIBS}
XML_CFLAGS $ ${XML_CFLAGS}
DEPS_LIBS $ ${DEPS_LIBS}
Python : ${PYTHON}
OPTIONAL FEATURES:
C++ standard level : ${CXX_STANDARD}
libdw has the dwarf_getalt function : ${FOUND_DWARF_GETALT_IN_LIBDW}
Enable inlined-only xxhash library : ${ENABLE_INLINED_XXHASH}
Enable rpm support in abipkgdiff : ${ENABLE_RPM}
Enable rpm/zstd in abipkgdiff testing : ${ENABLE_RPM_ZSTD}
Enable abilint --show-type-use <type-id> : ${ENABLE_SHOW_TYPE_USE_IN_ABILINT}
Enable self comparison debugging : ${ENABLE_DEBUG_SELF_COMPARISON}
Enable type canonicalization debugging : ${ENABLE_DEBUG_TYPE_CANONICALIZATION}
Enable propagated canonical type debugging : ${ENABLE_DEBUG_CT_PROPAGATION}
Enable deb support in abipkgdiff : ${ENABLE_DEB}
Enable GNU tar archive support in abipkgdiff : ${ENABLE_TAR}
Enable bash completion : ${ENABLE_BASH_COMPLETION}
Enable fedabipkgdiff : ${ENABLE_FEDABIPKGDIFF}
Enable abidb : ${ENABLE_ABIDB}
Enable python 3 : ${ENABLE_PYTHON3}
Enable CTF front-end : ${ENABLE_CTF}
Enable BTF front-end : ${ENABLE_BTF}
Enable Big Libabigail tests : ${ENABLE_BIG_TESTS}
Enable running tests under Valgrind : ${enable_valgrind}
Enable build with -fsanitize=address : ${ENABLE_ASAN}
Enable build with -fsanitize=memory : ${ENABLE_MSAN}
+28 -4
View File
@@ -91,7 +91,26 @@
[suppress_type]
soname_regexp = libwebkit2?gtk-.*\\.so.*
name_regexp = (^std::.*|WebCore::.*|WebKit::.*)
name_regexp = ^std::.*
drop = true
[suppress_type]
# Transform all C++ types in the WebCore and WebKit namespaces into
# opaque types. These are essentially internal types of libwebkit2
# anyway. This greatly reduces the size of the in-memory working set.
label = libabigail::OPAQUE_TYPE_LABEL
soname_regexp = libwebkit2?gtk-.*\\.so.*
name_regexp = (^WebCore::.*|^WebKit::.*)
drop = true
[suppress_type]
# All structs that don't start with either WebKit* or _WebKit are
# considered internal types and so are transform into opaque types.
# This helps to reduce the size of the in-memory working set further.
label = libabigail::OPAQUE_TYPE_LABEL
soname_regexp = libwebkit2?gtk-.*\\.so.*
type_kind = struct
name_not_regexp = ^_?WebKit.*
drop = true
#######################################################
@@ -155,9 +174,14 @@
#########################################
[suppress_function]
# Suppress ABI change reports about functions starting with the name
# krb5int_* in libraries named libkrb5<something>.so
soname_regexp = libkrb5.*\\.so.*
name_regexp = ^krb5int_.*
# krb5int_*, or k5_ in various libraries of the krb5-libs package
# because they are private functions. Note that deleted functions
# are also suppressed.
soname_regexp = lib(krb5|k5crypto|gssrpc|kdb5|krb5support|gssapi_krb5).*\\.so.*
change_kind = all
name_regexp = (^krb5int|^k5)_.*
symbol_name_regexp = (^krb5int|^k5)_.*
##########################################
# End of krb5 suppression specifications
#########################################
+1676 -999
View File
File diff suppressed because it is too large Load Diff
+5 -1
View File
@@ -7,10 +7,14 @@ abidiff.rst \
abipkgdiff.rst \
abicompat.rst \
abidw.rst \
abidb.rst \
abilint.rst \
conf.py \
index.rst \
libabigail-concepts.rst \
abi-artifacts.rst \
abi-changes.rst \
suppression-specifications.rst \
libabigail-overview.rst \
libabigail-tools.rst \
fedabipkgdiff.rst \
@@ -173,7 +177,7 @@ texinfodocs =
if ENABLE_MANUAL
section1_manpages += abipkgdiff.1 abidiff.1 abidw.1 abilint.1 abicompat.1
section1_manpages += abipkgdiff.1 abidiff.1 abidw.1 abidb.1 abilint.1 abicompat.1
section7_manpages += libabigail.7
manpages += $(section1_manpages) $(section7_manpages)
texinfodocs += abigail.info
+31
View File
@@ -0,0 +1,31 @@
.. _abi_artifacts_label:
ABI artifacts
=============
An ABI artifact is a relevant part of the ABI of a shared library or
program. Examples of ABI artifacts are exported types, variables,
functions, or `ELF`_ symbols exported by a shared library.
The set of ABI artifacts for a binary is called an ABI Corpus.
Scalar types have a name, a size and other scalar properties.
An aggregate type is generally constituted of sub-types.
For instance, class or union types are a kind of aggregate type. They
have a name, a size and members. Each member can be either
- a data member with a type representing a sub-type of the aggregate
type, an offset and a name
- or a function with a type representing another sub-type of the
aggregate type and a name. Some (virtual) member functions might
have an offset as well.
Another example of aggregate type is a function type, which is the
union of the return type and parameter types of the function.
Functions and variables are declarations that have a name and a type.
They are both associated with an `ELF`_ symbol.
.. _ELF: http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
+101
View File
@@ -0,0 +1,101 @@
.. _abi_change_label:
ABI changes
===========
Libabigail represents and analyzes changes of types, functions,
variables and ELF symbols.
Those different kinds of ABI artifact changes are categorized
depending on the impact they have on ABI compatibility.
ABI artifact changes are reported by tools like :ref:`abidiff
<abidiff_label>` and :ref:`abipkgdiff <abipkgdiff_label>` in textual
diff reports organized around the different kinds of changes listed
below.
Please note that users can instruct the tools to avoid emitting
reports about certain changes. This is done via :ref:`suppression
specifications <suppr_spec_label>`.
.. _harmlesschangeconcept_label:
Harmless changes
^^^^^^^^^^^^^^^^
A change in the diff report is considered harmless if it *does not*
cause any ABI compatibility issue. That is, it does not prevent an
application dynamically linked against a given version of a library to
keep working with the changed subsequent versions of the same library.
By default, :ref:`abidiff_label` and :ref:`abipkgdiff_label` filters
harmless changes from the diff report.
.. _harmfulchangeconcept_label:
Harmful changes
^^^^^^^^^^^^^^^^
An ABI change is considered harmful if it *might* cause ABI
compatibility issues. That is, it might prevent an application
dynamically linked against a given version of a library to keep
working with the changed subsequent versions of the same library.
Said otherwise, a harmful change is a change that is not harmless.
A harmful change absolutely needs to be reviewed by a human being to
know if it actually causes an ABI compatibility issue.
By default, :ref:`abidiff_label` shows harmful changes for functions
and global variables.
If the tool emits at least one harmful change then the bit
:ref:`ABIDIFF_ABI_CHANGE <abidiff_return_value_label>` of the
bit-field returned in the exit code is set to 1.
.. _incompatiblechangeconcept_label:
Incompatible changes
^^^^^^^^^^^^^^^^^^^^
An incompatible change is a harmful change that causes ABI
incompatibilities issues. In the colloquial language of programmers,
such a change is said to *break ABI*.
If the :ref:`abidiff_label` or :ref:`abipkgdiff_label` tool emits at
least one incompatible change then the bits
:ref:`ABIDIFF_ABI_INCOMPATIBLE_CHANGE <abidiff_return_value_label>`
and :ref:`ABIDIFF_ABI_CHANGE <abidiff_return_value_label>` of the
bit-field returned in the exit code are set to 1.
Changes recognized as ABI incompatible are the following:
* SONAME change of shared library
* change of the architecture of a binary
* remove of exported function or global variable ELF symbols (not
necessarily described by debug information)
* removal of exported functions or global variables that are described
by debug information.
* any incompatible change to the layout of the type which is used as a
type of a global variable or a return or parameter type of a
function. That incompatible layout type change might be:
* a modification to the size of the type
* or the removal of a data member
* or a modification of a data member offset
* or an incompatible change to a sub-type of the type
Please note that if a type is used neither as a type of a global
variable nor as a return or parameter type of a function, then
:ref:`abidiff_label` (or :ref:`abipkgdiff_label`) will not consider
an incompatible change of this type as an incompatible ABI change.
That change will just be considered as harmful. The
:ref:`ABIDIFF_ABI_CHANGE <abidiff_return_value_label>` bit of the
bit-field returned in the exit code is set to 1, meaning that the
change requires a human review. This is a current limitation of the
libabigail analysis framework that might be addressed in future
refinements.
+5
View File
@@ -77,6 +77,11 @@ Options
Do not show information about where in the *second shared library*
the respective type was changed.
* ``--btf``
When comparing binaries, extract ABI information from BTF debug
information, if present.
* ``--ctf``
When comparing binaries, extract ABI information from CTF debug
+174
View File
@@ -0,0 +1,174 @@
======
abidb
======
``abidb`` manages a git repository of abixml files describing shared
libraries, and checks binaries against them. ``elfutils`` and
``libabigail`` programs are used to query and process the binaries.
``abidb`` works well with ``debuginfod`` to fetch needed DWARF content
automatically.
.. _abidb_invocation_label:
Invocation
==========
::
abidb [OPTIONS] [--submit PATH1 PATH2 ...] [--check PATH1 PATH2 ...]
Common Options
==============
* ``--abicompat PATH``
Specify the path to the ``abicompat`` program to use. By default,
in the absence of this option, the ``abicompat`` program found in
directories listed in the $PATH environment is used.
* ``--abidw PATH``
Specify the path to the ``abidw`` program to use. By default,
in the absence of this option, the ``abidw`` program found in
directories listed in the $PATH environment is used.
* ``--distrobranch BRANCH``
Specify the git branch for the abixml files in the git repo. The
default is a string like DISTRO/VERSION/ARCHITECTURE, computed
from the running environment.
* ``--git REPO``
Specify the preexisting git working tree for abidb to submit to or
check against. The default is the current working directory. It
may be used concurrently by multiple "check" operations, but only
one "submit" operation.
* ``--help | -h``
Display a short help about the command and exit.
* ``--loglevel LOGLEVEL``
Specify the diagnostic level for messages to stderr. One of
``debug``, ``info``, ``warning``, ``error``, or ``critical``;
case-insensitive. The default is ``info``.
* ``--timeout SECONDS``
Specify a maximum limit to the execution time (in seconds) allowed
for the ``abidw`` and ``abicompat`` programs that are executed.
By default, no limit is set for the execution time of these
programs.
Submit Options
==============
* ``--archive | -Z .EXT[=CMD]``
Designate PATH names with a ``.EXT`` suffix to be treated as
archives. If ``CMD`` is present, pipe the PATH through the given
shell command, otherwise pass as if through ``cat``. The
resulting stream is then opened by ``libarchive``, to enumerate
the contents of a wide variety of possible archive file format.
Process each file in the archive individually into abixml.
For example, ``-Z .zip`` will process each file in a zip file, and
``-Z .deb='dpkg-deb --fsys-tarfile'`` will process each payload file
in a Debian archive.
* ``--filter REGEX``
Limit files selected for abixml extraction to those that match the
given regular expression. The default is ``/lib.*\.so``, as a
heuristic to identify shared libraries.
* ``--submit PATH1 PATH2 ...``
Using ``abidw``, extract abixml for each of the listed files,
generally shared libraries, subject to the filename filter and the
archive decoding options. Save the output of each ``abidw`` run
into the selected distrobranch of the selected git repo. If
``--submit`` and ``--check`` are both given, do submit operations
first.
* ``--sysroot PREFIX``
Specify the a prefix path that is to be removed from submitted
file names.
Check Options
=============
* ``--check PATH1 PATH2 ...``
Using ``abidiff``, compare each of the listed file, generally
executables, against abixml documents for selected versions for
all shared libraries needed by the executable. These are listed
by enumerating the dynamic segment tags ``DT_NEEDED`` of the
executable.
* ``--ld-library-path DIR1:DIR2:DIR3...``
Select the search paths for abixml documents used to locate any
particular ``SONAME`` . The first given directory wins. However,
all versions of the same ``SONAME`` in that directory are selected
for comparison. The default is unspecified, which means to search
for all matching ``SONAME`` entries in the distrobranch,
regardless of specific directory.
Exit Code
=========
In case of successful submission and/or checking of all paths, the
exit code is 0.
In case of error, the exit code of ``abidb`` is nonzero, and a brief
listing of the binaries unable to be submitted and/or checked is
printed.
Git Repository Schema
=====================
``abidb`` stores abixml documents in a git repo with the following
naming schema within the distrobranch:
1. The directory path leading to the shared library file
2. The SONAME of the shared library file, as a subdirectory name
3. A file named BUILDID.xml, where ``BUILDID`` is the hexadecimal ELF
build-id note of the shared library.
For example:
+---------------------------+-------------------------------------------------------------------+
|shared library file name |abixml path in git |
+---------------------------+-------------------------------------------------------------------+
| /usr/lib64/libc.so.6.2.32 | /usr/lib64/libc.so.6/788cdd41a15985bf8e0a48d213a46e07d58822df.xml |
| /usr/lib64/libc.so.6.2.33 | /usr/lib64/libc.so.6/e2ca832f1c2112aea9d7b9bc639e97e873a6b516.xml |
| /lib/ld-linux.so.2 | /lib/ld-linux.so.2/b65f3c15b129f33f44f504da1719926aec03c07d.xml |
+---------------------------+-------------------------------------------------------------------+
The intent of including the buildid in the name is so that as a distro
is updated with multiple versions of a given shared library, they can
be represented nearby but non-conflicting. The ``SONAME`` is used in
the second-last name component, inspired the behavior of ``ld.so`` and
``ldconfig``, which rely on symbolic links to map references from
the ``SONAME`` to an actual file.
See Also
=======
* ELF: http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
* DWARF: https://www.dwarfstd.org
* Debuginfod: https://sourceware.org/elfutils/Debuginfod.html
* Git: https://git-scm.com/
* Libarchive: https://www.libarchive.org/
+517 -381
View File
File diff suppressed because it is too large Load Diff
+335 -235
View File
@@ -1,3 +1,4 @@
.. _abidw_label:
======
abidw
@@ -40,18 +41,23 @@ Invocation
Options
=======
* ``--help | -h``
* ``--abidiff``
Display a short help about the command and exit.
Load the ABI of the ELF binary given in argument, save it in
libabigail's XML format in a temporary file; read the ABI from the
temporary XML file and compare the ABI that has been read back
against the ABI of the ELF binary given in argument. The ABIs
should compare equal. If they don't, the program emits a
diagnostic and exits with a non-zero code.
* ``--version | -v``
This is a debugging and sanity check option.
Display the version of the program and exit.
* ``--abixml-version``
Display the version of the ABIXML format emitted by this program and exit.
* ``--add-binaries`` <*bin1,bin2,...*>
For each of the comma-separated binaries given in argument to this
@@ -61,20 +67,6 @@ Options
Group) made of the binary denoted by the Argument of
``abidw``. That corpus group is then serialized out.
* ``--follow-dependencies``
For each dependency of the input binary of ``abidw``, if it is
found in the directory specified by the ``--added-binaries-dir``
option, then construct an ABI corpus out of the dependency and add
it to a set of ABI corpora (called an ABI Corpus Group) along with
the ABI corpus of the input binary of the program. The ABI Corpus
Group is then serialized out.
* ``--list-dependencies``
For each dependency of the input binary of``abidw``, if it's found
in the directory specified by the ``--added-binaries-dir`` option,
then the name of the dependency is printed out.
* ``--added-binaries-dir | --abd`` <*dir-path*>
@@ -87,159 +79,6 @@ Options
corpus and added to the set of ABI corpora (called an ABI corpus
group) built and serialized.
* ``--debug-info-dir | -d`` <*dir-path*>
In cases where the debug info for *path-to-elf-file* is in a
separate file that is located in a non-standard place, this tells
``abidw`` where to look for that debug info file.
Note that *dir-path* must point to the root directory under which
the debug information is arranged in a tree-like manner. Under
Red Hat based systems, that directory is usually
``<root>/usr/lib/debug``.
This option can be provided several times with different root
directories. In that case, ``abidw`` will potentially look into
all those root directories to find the split debug info for the
elf file.
Note that this option is not mandatory for split debug information
installed by your system's package manager because then
``abidw`` knows where to find it.
* ``--out-file`` <*file-path*>
This option instructs ``abidw`` to emit the XML representation of
*path-to-elf-file* into the file *file-path*, rather than emitting
it to its standard output.
* ``--noout``
This option instructs ``abidw`` to not emit the XML representation
of the ABI. So it only reads the ELF and debug information,
builds the internal representation of the ABI and exits. This
option is usually useful for debugging purposes.
* ``--no-corpus-path``
Do not emit the path attribute for the ABI corpus.
* ``--suppressions | suppr`` <*path-to-suppression-specifications-file*>
Use a :ref:`suppression specification <suppr_spec_label>` file
located at *path-to-suppression-specifications-file*. Note that
this option can appear multiple times on the command line. In
that case, all of the provided suppression specification files are
taken into account. ABI artifacts matched by the suppression
specifications are suppressed from the output of this tool.
* ``--kmi-whitelist | -kaw`` <*path-to-whitelist*>
When analyzing a `Linux Kernel`_ binary, this option points to the
white list of names of ELF symbols of functions and variables
which ABI must be written out. That white list is called a "
Kernel Module Interface white list". This is because for the
Kernel, we don't talk about the ABI; we rather talk about the
interface between the Kernel and its module. Hence the term
``KMI`` rather than ``ABI``
Any other function or variable which ELF symbol are not present in
that white list will not be considered by the KMI writing process.
If this option is not provided -- thus if no white list is
provided -- then the entire KMI, that is, all publicly defined and
exported functions and global variables by the `Linux Kernel`_
binaries is emitted.
* ``--linux-tree | --lt``
Make ``abidw`` to consider the input path as a path to a directory
containing the vmlinux binary as several kernel modules binaries.
In that case, this program emits the representation of the Kernel
Module Interface (KMI) on the standard output.
Below is an example of usage of ``abidw`` on a `Linux Kernel`_
tree.
First, checkout a `Linux Kernel`_ source tree and build it. Then
install the kernel modules in a directory somewhere. Copy the
vmlinux binary into that directory too. And then serialize the
KMI of that kernel to disk, using ``abidw``: ::
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
$ cd linux && git checkout v4.5
$ make allyesconfig all
$ mkdir build-output
$ make INSTALL_MOD_PATH=./build-output modules_install
$ cp vmlinux build-output/modules/4.5.0
$ abidw --linux-tree build-output/modules/4.5.0 > build-output/linux-4.5.0.kmi
* ``--headers-dir | --hd`` <headers-directory-path-1>
Specifies where to find the public headers of the binary that the
tool has to consider. The tool will thus filter out types that
are not defined in public headers.
Note that several public header directories can be specified for
the binary to consider. In that case the ``--header-dir`` option
should be present several times on the command line, like in the
following example: ::
$ abidw --header-dir /some/path \
--header-dir /some/other/path \
binary > binary.abi
* ``--header-file | --hf`` <header-file-path>
Specifies where to find one of the public headers of the abi file
that the tool has to consider. The tool will thus filter out
types that are not defined in public headers.
* ``--drop-private-types``
This option is to be used with the ``--headers-dir`` and/or
``header-file`` options. With this option, types that are *NOT*
defined in the headers are entirely dropped from the internal
representation build by Libabigail to represent the ABI and will
not end up in the abi XML file.
* ``--no-elf-needed``
Do not include the list of DT_NEEDED dependency names in the
corpus.
* ``--drop-undefined-syms``
With this option functions or variables for which the (exported)
ELF symbol is undefined are dropped from the internal
representation build by Libabigail to represent the ABI and will
not end up in the abi XML file.
* ``--exported-interfaces-only``
By default, when looking at the debug information accompanying a
binary, this tool analyzes the descriptions of the types reachable
by the interfaces (functions and variables) that are visible
outside of their translation unit. Once that analysis is done, an
ABI corpus is constructed by only considering the subset of types
reachable from interfaces associated to `ELF`_ symbols that are
defined and exported by the binary. It's that final ABI corpus
which textual representation is saved as ``ABIXML``.
The problem with that approach however is that analyzing all the
interfaces that are visible from outside their translation unit
can amount to a lot of data, especially when those binaries are
applications, as opposed to shared libraries. One example of such
applications is the `Linux Kernel`_. Analyzing massive ABI
corpora like these can be extremely slow.
To mitigate that performance issue, this option allows libabigail
to only analyze types that are reachable from interfaces
associated with defined and exported `ELF`_ symbols.
Note that this option is turned on by default when analyzing the
`Linux Kernel`_. Otherwise, it's turned off by default.
* ``--allow-non-exported-interfaces``
@@ -266,16 +105,20 @@ Options
Note that this option is turned on by default, unless we are in
the presence of the `Linux Kernel`_.
* ``--no-linux-kernel-mode``
Without this option, if abipkgiff detects that the binaries it is
looking at are Linux Kernel binaries (either vmlinux or modules)
then it only considers functions and variables which ELF symbols
are listed in the __ksymtab and __ksymtab_gpl sections.
* ``--annotate``
Annotate the ABIXML output with comments above most elements. The
comments are made of the pretty-printed form types, declaration or
even ELF symbols. The purpose is to make the ABIXML output more
human-readable for debugging or documenting purposes.
* ``--btf``
Extract ABI information from `BTF`_ debug information, if present in
the given object.
With this option, abipkgdiff considers the binary as a non-special
ELF binary. It thus considers functions and variables which are
defined and exported in the ELF sense.
* ``--check-alternate-debug-info`` <*elf-path*>
@@ -286,33 +129,6 @@ Options
alternate debug info file found. Otherwise, it emits an error
code.
* ``--no-show-locs``
In the emitted ABI representation, do not show file, line or column
where ABI artifacts are defined.
* ``--no-parameter-names``
In the emitted ABI representation, do not show names of function
parameters, just the types.
* ``--no-write-default-sizes``
In the XML ABI representation, do not write the size-in-bits for
pointer type definitions, reference type definitions, function
declarations and function types when they are equal to the default
address size of the translation unit. Note that libabigail before
1.8 will not set the default size and will interpret types without
a size-in-bits attribute as zero sized.
* ``--type-id-style`` <``sequence``|``hash``>
This option controls how types are idenfied in the generated XML
files. The default ``sequence`` style just numbers (with
``type-id-`` as prefix) the types in the order they are
encountered. The ``hash`` style uses a (stable, portable) hash of
libabigail's internal type names and is intended to make the XML
files easier to diff.
* ``--check-alternate-debug-info-base-name`` <*elf-path*>
@@ -320,27 +136,8 @@ Options
Like ``--check-alternate-debug-info``, but in the success message,
only mention the base name of the debug info file; not its full path.
* ``--load-all-types``
By default, ``libabigail`` (and thus ``abidw``) only loads types
that are reachable from functions and variables declarations that
are publicly defined and exported by the binary. So only those
types are present in the output of ``abidw``. This option however
makes ``abidw`` load *all* the types defined in the binaries, even
those that are not reachable from public declarations.
* ``--abidiff``
Load the ABI of the ELF binary given in argument, save it in
libabigail's XML format in a temporary file; read the ABI from the
temporary XML file and compare the ABI that has been read back
against the ABI of the ELF binary given in argument. The ABIs
should compare equal. If they don't, the program emits a
diagnostic and exits with a non-zero code.
This is a debugging and sanity check option.
* ``--debug-abidiff``
* ``--debug-abidiff``
Same as ``--abidiff`` but in debug mode. In this mode, error
messages are emitted for types which fail type canonicalization.
@@ -349,7 +146,35 @@ Options
it the libabigail package needs to be configured with
the --enable-debug-self-comparison option.
* ``--debug-type-canonicalization | --debug-tc``
* ``--ctf``
Extract ABI information from `CTF`_ debug information, if present in
the given object.
* ``--debug-info-dir | -d`` <*dir-path*>
In cases where the debug info for *path-to-elf-file* is in a
separate file that is located in a non-standard place, this tells
``abidw`` where to look for that debug info file.
Note that *dir-path* must point to the root directory under which
the debug information is arranged in a tree-like manner. Under
Red Hat based systems, that directory is usually
``<root>/usr/lib/debug``.
This option can be provided several times with different root
directories. In that case, ``abidw`` will potentially look into
all those root directories to find the split debug info for the
elf file.
Note that this option is not mandatory for split debug information
installed by your system's package manager because then
``abidw`` knows where to find it.
* ``--debug-type-canonicalization | --debug-tc``
Debug the type canonicalization process. This is done by using
structural and canonical equality when canonicalizing every single
@@ -362,6 +187,183 @@ Options
This option is available only if the package was configured with
the --enable-debug-type-canonicalization option.
.. _abidw_drop_private_types_option_label:
* ``--drop-private-types``
This option is implicitly set by option :ref:`--headers-dir
<abidw_header_dir_option_label>` and :ref:`--header-file
<abidw_header_file_option_label>` options.
With this option, types that are *NOT* defined in the headers are
entirely dropped from the internal representation build by
Libabigail to represent the ABI and will not end up in the abi XML
file.
This option is provided or compatibility reasons only and should
not be explicitly used anymore.
* ``--drop-undefined-syms``
With this option functions or variables for which the (exported)
ELF symbol is undefined are dropped from the internal
representation build by Libabigail to represent the ABI and will
not end up in the abi XML file.
* ``--exported-interfaces-only``
By default, when looking at the debug information accompanying a
binary, this tool analyzes the descriptions of the types reachable
by the interfaces (functions and variables) that are visible
outside of their translation unit. Once that analysis is done, an
ABI corpus is constructed by only considering the subset of types
reachable from interfaces associated to `ELF`_ symbols that are
defined and exported by the binary. It's that final ABI corpus
which textual representation is saved as ``ABIXML``.
The problem with that approach however is that analyzing all the
interfaces that are visible from outside their translation unit
can amount to a lot of data, especially when those binaries are
applications, as opposed to shared libraries. One example of such
applications is the `Linux Kernel`_. Analyzing massive ABI
corpora like these can be extremely slow.
To mitigate that performance issue, this option allows libabigail
to only analyze types that are reachable from interfaces
associated with defined and exported `ELF`_ symbols.
Note that this option is turned on by default when analyzing the
`Linux Kernel`_. Otherwise, it's turned off by default.
* ``--follow-dependencies``
For each dependency of the input binary of ``abidw``, if it is
found in the directory specified by the ``--added-binaries-dir``
option, then construct an ABI corpus out of the dependency and add
it to a set of ABI corpora (called an ABI Corpus Group) along with
the ABI corpus of the input binary of the program. The ABI Corpus
Group is then serialized out.
.. _abidw_force_early_suppression_option_label:
* ``--force-early-suppression``
This option must be used alongside option :ref:`--suppression
<abidw_suppressions_option_label>`.
It forces :ref:`suppression specifications <suppr_spec_label>` to
be applied in :ref:`early suppression mode
<early_suppression_mode_label>`. Artifacts of the internal
representation that are matched by suppression specifications are
thus suppressed from memory.
If this option is not used then only suppression specifications
with the :ref:`drop property set to 'yes' <drop_property_label>`
are effective. All other suppression specification directives
will appear to be ignored.
.. _abidw_header_dir_option_label:
* ``--headers-dir | --hd`` <headers-directory-path-1>
Specifies where to find the public headers of the binary that the
tool has to consider. The tool will thus filter out types that
are not defined in public headers. This option implicitly sets
option :ref:`--drop-private-types
<abidw_drop_private_types_option_label>`.
Note that several public header directories can be specified for
the binary to consider. In that case the ``--header-dir`` option
should be present several times on the command line, like in the
following example: ::
$ abidw --header-dir /some/path \
--header-dir /some/other/path \
binary > binary.abi
.. _abidw_header_file_option_label:
* ``--header-file | --hf`` <header-file-path>
Specifies where to find one of the public headers of the abi file
that the tool has to consider. The tool will thus filter out
types that are not defined in public headers.
This option implicitly sets option :ref:`--drop-private-types
<abidw_drop_private_types_option_label>`.
* ``--help | -h``
Display a short help about the command and exit.
* ``--kmi-whitelist | --kmi-stablelist |-w`` <*path-to-stablelist*>
When analyzing a `Linux Kernel`_ binary, this option points to the
list of names of ELF symbols of functions and variables which ABI
must be written out. Any function or variable with a name that is
not included in that list will not ignored. That list is called a
" Kernel Module Interface stable list". This is because for the
Kernel, we don't talk about the ABI; we rather talk about the
interface between the Kernel and its module. Hence the term
``KMI`` rather than ``KABI``.
Any other function or variable which ELF symbol are not present in
that stable list will not be considered by the KMI writing
process.
If this option is not provided -- thus if no stable list is
provided -- then the entire KMI, that is, all publicly defined and
exported functions and global variables by the `Linux Kernel`_
binaries is emitted.
* ``--list-dependencies``
For each dependency of the input binary of``abidw``, if it's found
in the directory specified by the ``--added-binaries-dir`` option,
then the name of the dependency is printed out.
* ``--load-all-types``
By default, ``libabigail`` (and thus ``abidw``) only loads types
that are reachable from functions and variables declarations that
are publicly defined and exported by the binary. So only those
types are present in the output of ``abidw``. This option however
makes ``abidw`` load *all* the types defined in the binaries, even
those that are not reachable from public declarations.
* ``--linux-tree | --lt``
Make ``abidw`` to consider the input path as a path to a directory
containing the vmlinux binary as several kernel modules binaries.
In that case, this program emits the representation of the Kernel
Module Interface (KMI) on the standard output.
Below is an example of usage of ``abidw`` on a `Linux Kernel`_
tree.
First, checkout a `Linux Kernel`_ source tree and build it. Then
install the kernel modules in a directory somewhere. Copy the
vmlinux binary into that directory too. And then serialize the
KMI of that kernel to disk, using ``abidw``: ::
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
$ cd linux && git checkout v4.5
$ make allyesconfig all
$ mkdir build-output
$ make INSTALL_MOD_PATH=./build-output modules_install
$ cp vmlinux build-output/modules/4.5.0
$ abidw --linux-tree build-output/modules/4.5.0 > build-output/linux-4.5.0.kmi
* ``--no-assume-odr-for-cplusplus``
When analysing a binary originating from C++ code using `DWARF`_
@@ -373,6 +375,18 @@ Options
actually actually compare the types to determine if they are
equal.
* ``--no-corpus-path``
Do not emit the path attribute for the ABI corpus.
* ``--no-elf-needed``
Do not include the list of DT_NEEDED dependency names in the
corpus.
* ``--no-leverage-dwarf-factorization``
When analysing a binary which `DWARF`_ debug information was
@@ -382,27 +396,113 @@ Options
This option disables those optimizations.
* ``--ctf``
Extract ABI information from `CTF`_ debug information, if present in
the given object.
* ``--no-load-undefined-interfaces``
* ``--annotate``
By default, ``libabigail`` (and thus ``abidw``) loads information
about undefined function and variable symbols as well as functions
and variables that are associated with those undefined symbols.
Those are called undefined interfaces. This option however makes
makes ``abidw`` avoid loading information about undefined
interfaces. The resulting XML file thus doesn't contain
information about those undefined interfaces.
* ``--no-linux-kernel-mode``
Without this option, if abipkgiff detects that the binaries it is
looking at are Linux Kernel binaries (either vmlinux or modules)
then it only considers functions and variables which ELF symbols
are listed in the __ksymtab and __ksymtab_gpl sections.
With this option, abipkgdiff considers the binary as a non-special
ELF binary. It thus considers functions and variables which are
defined and exported in the ELF sense.
* ``--noout``
This option instructs ``abidw`` to not emit the XML representation
of the ABI. So it only reads the ELF and debug information,
builds the internal representation of the ABI and exits. This
option is usually useful for debugging purposes.
* ``--no-parameter-names``
In the emitted ABI representation, do not show names of function
parameters, just the types.
* ``--no-show-locs``
In the emitted ABI representation, do not show file, line or column
where ABI artifacts are defined.
* ``--no-write-default-sizes``
In the XML ABI representation, do not write the size-in-bits for
pointer type definitions, reference type definitions, function
declarations and function types when they are equal to the default
address size of the translation unit. Note that libabigail before
1.8 will not set the default size and will interpret types without
a size-in-bits attribute as zero sized.
* ``--out-file | -o`` <*file-path*>
This option instructs ``abidw`` to emit the XML representation of
*path-to-elf-file* into the file *file-path*, rather than emitting
it to its standard output.
Annotate the ABIXML output with comments above most elements. The
comments are made of the pretty-printed form types, declaration or
even ELF symbols. The purpose is to make the ABIXML output more
human-readable for debugging or documenting purposes.
* ``--stats``
Emit statistics about various internal things.
.. _abidw_suppressions_option_label:
* ``--suppressions | suppr`` <*path-to-suppression-specifications-file*>
Use a :ref:`suppression specification <suppr_spec_label>` file
located at *path-to-suppression-specifications-file*. Note that
this option can appear multiple times on the command line. In
that case, all of the provided suppression specification files are
taken into account. ABI artifacts matched by the suppression
specifications are suppressed from the output of this tool.
Only suppression specifications that have the :ref:`drop property
set to 'yes' <drop_property_label>` are going to be effective.
All other suppression specification directives will appear as
being ignored, unless the command line option
:ref:`--force-early-suppression
<abidw_force_early_suppression_option_label>` is provided.
* ``--type-id-style`` <``sequence``|``hash``>
This option controls how types are idenfied in the generated XML
files. The default ``sequence`` style just numbers (with
``type-id-`` as prefix) the types in the order they are
encountered. The ``hash`` style uses a (stable, portable) hash of
libabigail's internal type names and is intended to make the XML
files easier to diff.
* ``--verbose``
Emit verbose logs about the progress of miscellaneous internal
things.
* ``--version | -v``
Display the version of the program and exit.
Usage examples
==============
+41 -18
View File
@@ -27,13 +27,19 @@ Invocation
Options
=======
* ``--help``
* ``--annotate``
Display a short help message and exits.
Annotate the ABIXML output with comments above most elements. The
comments are made of the pretty-printed form of types, declaration
or even ELF symbols. The purpose is to make the ABIXML output
more human-readable for debugging or documenting purposes.
* `--version | -v`
Display the version of the program and exit.
* ``--ctf``
Extract ABI information from CTF debug information, if present in
the given object.
* ``--debug-info-dir`` <*path*>
@@ -50,17 +56,39 @@ Options
information installed by your system's package manager because
then ``abidiff`` knows where to find it.
* ``--diff``
For XML inputs, perform a text diff between the input and the
memory model saved back to disk. This can help to spot issues in
the handling of the XML format by the underlying Libabigail library.
* ``--header-file | --hf`` <header-file-path>
Specifies where to find one of the public headers of the abi file
that the tool has to consider. The tool will thus filter out
types that are not defined in public headers.
* ``--headers-dir | --hd`` <headers-directory-path-1>
Specifies where to find the public headers of the first shared
library that the tool has to consider. The tool will thus filter
out types that are not defined in public headers.
* ``--help``
Display a short help message and exits.
* ``--noout``
Do not display anything on standard output. The return code of
the command is the only way to know if the command succeeded.
* ``--suppressions | suppr`` <*path-to-suppression-specifications-file*>
Use a :ref:`suppression specification <suppr_spec_label>` file
@@ -70,30 +98,25 @@ Options
taken into account. ABI artifacts matched by the suppression
specifications are suppressed from the output of this tool.
* ``--headers-dir | --hd`` <headers-directory-path-1>
Specifies where to find the public headers of the first shared
library that the tool has to consider. The tool will thus filter
out types that are not defined in public headers.
* ``--header-file | --hf`` <header-file-path>
Specifies where to find one of the public headers of the abi file
that the tool has to consider. The tool will thus filter out
types that are not defined in public headers.
* ``--stdin | --``
Read the input content from standard input.
* ``--tu``
Expect the input XML to represent a single translation unit.
* ``--ctf``
* `--verbose`
Shows verbose messages about internal stuff. This is used to
debug the tool and its underlying library.
* `--version | -v`
Display the version of the program and exit.
Extract ABI information from CTF debug information, if present in
the given object.
.. _ELF: http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
.. _DWARF: http://www.dwarfstd.org
+312 -240
View File
@@ -5,13 +5,17 @@ abipkgdiff
===========
``abipkgdiff`` compares the Application Binary Interfaces (ABI) of the
`ELF`_ binaries contained in two software packages. The software
package formats currently supported are `Deb`_, `RPM`_, `tar`_
archives (either compressed or not) and plain directories that contain
binaries.
`ELF`_ binaries contained in two sets of software packages. The
software package formats currently supported are `Deb`_, `RPM`_,
`tar`_ archives (either compressed or not) and plain directories that
contain binaries.
The ABI of the binaries contained in the second set of packages is
compared against the ABI of the binaries contained in the first set of
packages.
For a comprehensive ABI change report that includes changes about
function and variable sub-types, the two input packages must be
function and variable sub-types, the two input package sets must be
accompanied with their debug information packages that contain debug
information either in `DWARF`_, `CTF`_ or in `BTF`_ formats. Please
note however that some packages contain binaries that embed the debug
@@ -34,11 +38,21 @@ Invocation
::
abipkgdiff [option] <package1> <package2>
abipkgdiff [options] <package1> <package2>
``package1`` and ``package2`` are the packages that contain the
binaries to be compared.
An alternate invocation style would be:
::
abipkgdiff [options] --set1 <pkg1-v1> <pkg2-v1> <pkg3-v1> \
--set2 <pkg1-v2> <pkg2-v2> <pkg3-v2>
where the ABI of binaries contained in the second set of packages are
compared against binaries contained in the first set of packages.
Environment
===========
@@ -80,13 +94,43 @@ documented further below) to provide a suppression specification.
Options
=======
* ``--help | -h``
* ``--allow-non-exported-interfaces``
Display a short help about the command and exit.
When looking at the debug information accompanying a binary, this
tool analyzes the descriptions of the types reachable by the
interfaces (functions and variables) that are visible outside of
their translation unit. Once that analysis is done, an ABI corpus
is constructed by only considering the subset of types reachable
from interfaces associated to `ELF`_ symbols that are defined and
exported by the binary. It's those final ABI Corpora that are
compared by this tool.
* `--version | -v`
The problem with that approach however is that analyzing all the
interfaces that are visible from outside their translation unit
can amount to a lot of data, especially when those binaries are
applications, as opposed to shared libraries. One example of such
applications is the `Linux Kernel`_. Analyzing massive ABI
Corpora like these can be extremely slow.
In the presence of an "average sized" binary however one can
afford having libabigail analyze all interfaces that are visible
outside of their translation unit, using this option.
Note that this option is turned on by default, unless we are in
the presence of the `Linux Kernel`_.
* ``--btf``
This is used to compare packages with `BTF`_ debug information,
if present.
* ``--ctf``
This is used to compare packages with `CTF`_ debug information,
if present.
Display the version of the program and exit.
* ``--debug-info-pkg1 | --d1`` <path>
@@ -99,6 +143,7 @@ Options
instances of this options can be provided, along with those
several different debug info packages.
* ``--debug-info-pkg2 | --d2`` <path>
For cases where the debug information for *package2* is split out
@@ -110,6 +155,7 @@ Options
instances of this options can be provided, along with those
several different debug info packages.
* ``--devel-pkg1 | --devel1`` <path>
Specifies where to find the `Development Package`_ associated with
@@ -120,6 +166,7 @@ Options
filters out reports about ABI changes to types that are *NOT*
defined in these header files.
* ``--devel-pkg2 | --devel2`` <path>
Specifies where to find the `Development Package`_ associated with
@@ -130,6 +177,7 @@ Options
filters out reports about ABI changes to types that are *NOT*
defined in these header files.
* ``--drop-private-types``
This option is to be used with the ``--devel-pkg1`` and
@@ -148,24 +196,106 @@ Options
consumption of the tool on binaries with a lot of publicly defined
and exported types.
* ``--dso-only``
Compare ELF files that are shared libraries, only. Do not compare
executable files, for instance.
* ``--private-dso``
By default, ``abipkgdiff`` does not compare DSOs that are private
to the RPM package. A private DSO is a DSO which SONAME is *NOT*
advertised in the "provides" property of the RPM.
* ``--exported-interfaces-only``
This option instructs ``abipkgdiff`` to *also* compare DSOs that
are *NOT* advertised in the "provides" property of the RPM.
By default, when looking at the debug information accompanying a
binary, this tool analyzes the descriptions of the types reachable
by the interfaces (functions and variables) that are visible
outside of their translation unit. Once that analysis is done, an
ABI corpus is constructed by only considering the subset of types
reachable from interfaces associated to `ELF`_ symbols that are
defined and exported by the binary. It's those final ABI Corpora
that are compared by this tool.
The problem with that approach however is that analyzing all the
interfaces that are visible from outside their translation unit
can amount to a lot of data, especially when those binaries are
applications, as opposed to shared libraries. One example of such
applications is the `Linux Kernel`_. Analyzing massive ABI
corpora like these can be extremely slow.
To mitigate that performance issue, this option allows libabigail
to only analyze types that are reachable from interfaces
associated with defined and exported `ELF`_ symbols.
Note that this option is turned on by default when analyzing the
`Linux Kernel`_. Otherwise, it's turned off by default.
* ``--fail-no-dbg``
Make the program fail and return a non-zero exit code if couldn't
read any of the debug information that comes from the debug info
packages that were given on the command line. If no debug info
package were provided on the command line then this option is not
active.
Note that the non-zero exit code returned by the program as a
result of this option is the constant ``ABIDIFF_ERROR``. To know
the numerical value of that constant, please refer to the
:ref:`exit code documentation <abidiff_return_value_label>`.
* ``--full-impact|-f``
When comparing two Linux Kernel packages, this function instructs
``abipkgdiff`` to emit the so-called ``full impact report``, which
is the default report kind emitted by the ``abidiff`` tool: ::
$ abidiff libtest-v0.so libtest-v1.so
Functions changes summary: 0 Removed, 1 Changed, 0 Added function
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
1 function with some indirect sub-type change:
[C]'function void fn(C&)' at test-v1.cc:13:1 has some indirect sub-type changes:
parameter 1 of type 'C&' has sub-type changes:
in referenced type 'struct C' at test-v1.cc:7:1:
type size hasn't changed
1 data member change:
type of 'leaf* C::m0' changed:
in pointed to type 'struct leaf' at test-v1.cc:1:1:
type size changed from 32 to 64 bits
1 data member insertion:
'char leaf::m1', at offset 32 (in bits) at test-v1.cc:4:1
$
* ``--harmless``
In the diff report, display only the :ref:`harmless
<harmlesschangeconcept_label>` changes. By default, the harmless
changes are filtered out of the diff report keep the clutter to a
minimum and have a greater chance to spot real ABI issues.
* ``--help | -h``
Display a short help about the command and exit.
* ``--impacted-interfaces``
When showing leaf changes, this option instructs abipkgdiff to
show the list of impacted interfaces. This option is thus to be
used in addition to the ``--leaf-changes-only`` option, or, when
comparing two Linux Kernel packages. Otherwise, it's simply
ignored.
* ``--keep-tmp-files``
Do not erase the temporary directory files that are created during
the execution of the tool.
Please note that the fact that (by default) ``abipkgdiff`` skips
private DSO is a feature that is available only for RPMs, at the
moment. We would happily accept patches adding that feature for
other package formats.
* ``--leaf-changes-only|-l`` only show leaf changes, so don't show
impact analysis report. This option implies ``--redundant``
@@ -228,38 +358,89 @@ Options
option ``--full-impact`` which is documented later below.
* ``--impacted-interfaces``
* ``--linux-kernel-abi-whitelist | -w`` <*path-to-whitelist*>
When showing leaf changes, this option instructs abipkgdiff to
show the list of impacted interfaces. This option is thus to be
used in addition to the ``--leaf-changes-only`` option, or, when
comparing two Linux Kernel packages. Otherwise, it's simply
ignored.
When comparing two Linux kernel RPM packages, this option points
to the white list of names of ELF symbols of functions and
variables that must be compared for ABI changes. That white list
is called a "Linux kernel ABI white list".
* ``--full-impact|-f``
Any other function or variable which ELF symbol are not present in
that white list will not be considered by the ABI comparison
process.
When comparing two Linux Kernel packages, this function instructs
``abipkgdiff`` to emit the so-called ``full impact report``, which
is the default report kind emitted by the ``abidiff`` tool: ::
If this option is not provided -- thus if no white list is
provided -- then the ABI of all publicly defined and exported
functions and global variables by the Linux Kernel binaries are
compared.
$ abidiff libtest-v0.so libtest-v1.so
Functions changes summary: 0 Removed, 1 Changed, 0 Added function
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
Please note that if a white list package is given in parameter,
this option handles it just fine, like if the --wp option was
used.
1 function with some indirect sub-type change:
[C]'function void fn(C&)' at test-v1.cc:13:1 has some indirect sub-type changes:
parameter 1 of type 'C&' has sub-type changes:
in referenced type 'struct C' at test-v1.cc:7:1:
type size hasn't changed
1 data member change:
type of 'leaf* C::m0' changed:
in pointed to type 'struct leaf' at test-v1.cc:1:1:
type size changed from 32 to 64 bits
1 data member insertion:
'char leaf::m1', at offset 32 (in bits) at test-v1.cc:4:1
* ``--no-abignore``
$
Do not search the package for the presence of suppression files.
* ``--no-added-binaries``
Do not show the list of binaries that got added to the second
package.
Please note that the presence of such added binaries is not
considered like an ABI change by this tool; as such, it doesn't
have any impact on the exit code of the tool. It does only have
an informational value. Removed binaries are, however, considered
as an ABI change.
* ``--no-added-syms``
Do not show the list of functions, variables, or any symbol that
was added.
* ``--no-assume-odr-for-cplusplus``
When analysing a binary originating from C++ code using `DWARF`_
debug information, libabigail assumes the `One Definition Rule`_
to speed-up the analysis. In that case, when several types have
the same name in the binary, they are assumed to all be equal.
This option disables that assumption and instructs libabigail to
actually actually compare the types to determine if they are
equal.
* ``--no-default-suppression``
Do not load the :ref:`default suppression specification files
<abipkgdiff_default_supprs_label>`.
* ``--no-leverage-dwarf-factorization``
When analysing a binary which `DWARF`_ debug information was
processed with the `DWZ`_ tool, the type information is supposed
to be already factorized. That context is used by libabigail to
perform some speed optimizations.
This option disables those optimizations.
* ``--no-linkage-name``
In the resulting report, do not display the linkage names of
the added, removed, or changed functions or variables.
* ``--no-parallel``
By default, ``abipkgdiff`` will use all the processors it has available to
execute concurrently. This option tells it not to extract packages or run
comparisons in parallel.
* ``--non-reachable-types|-t``
@@ -284,55 +465,75 @@ Options
global functions and variables are analyzed, so the tool detects
and reports changes on these reachable types only.
* ``--exported-interfaces-only``
By default, when looking at the debug information accompanying a
binary, this tool analyzes the descriptions of the types reachable
by the interfaces (functions and variables) that are visible
outside of their translation unit. Once that analysis is done, an
ABI corpus is constructed by only considering the subset of types
reachable from interfaces associated to `ELF`_ symbols that are
defined and exported by the binary. It's those final ABI Corpora
that are compared by this tool.
* ``--no-show-locs``
The problem with that approach however is that analyzing all the
interfaces that are visible from outside their translation unit
can amount to a lot of data, especially when those binaries are
applications, as opposed to shared libraries. One example of such
applications is the `Linux Kernel`_. Analyzing massive ABI
corpora like these can be extremely slow.
Do not show information about where in the *second shared library*
the respective type was changed.
To mitigate that performance issue, this option allows libabigail
to only analyze types that are reachable from interfaces
associated with defined and exported `ELF`_ symbols.
Note that this option is turned on by default when analyzing the
`Linux Kernel`_. Otherwise, it's turned off by default.
* ``--no-show-relative-offset-changes``
* ``--allow-non-exported-interfaces``
Without this option, when the offset of a data member changes,
the change report not only mentions the older and newer offset,
but it also mentions by how many bits the data member changes.
With this option, the latter is not shown.
When looking at the debug information accompanying a binary, this
tool analyzes the descriptions of the types reachable by the
interfaces (functions and variables) that are visible outside of
their translation unit. Once that analysis is done, an ABI corpus
is constructed by only considering the subset of types reachable
from interfaces associated to `ELF`_ symbols that are defined and
exported by the binary. It's those final ABI Corpora that are
compared by this tool.
The problem with that approach however is that analyzing all the
interfaces that are visible from outside their translation unit
can amount to a lot of data, especially when those binaries are
applications, as opposed to shared libraries. One example of such
applications is the `Linux Kernel`_. Analyzing massive ABI
Corpora like these can be extremely slow.
* ``--no-unreferenced-symbols``
In the presence of an "average sized" binary however one can
afford having libabigail analyze all interfaces that are visible
outside of their translation unit, using this option.
In the resulting report, do not display change information about
function and variable symbols that are not referenced by any debug
information. Note that for these symbols not referenced by any
debug information, the change information displayed is either
added or removed symbols.
* ``--show-bits``
Show sizes and offsets in bits, not bytes. This option is
activated by default.
* ``--show-bytes``
Show sizes and offsets in bytes, not bits. By default, sizes and
offsets are shown in bits.
* ``--show-dec``
Show sizes and offsets in decimal base. This option is activated
by default.
* ``--show-hex``
Show sizes and offsets in hexadecimal base.
* ``--show-identical-binaries``
Show the names of the all binaries compared, including the
binaries whose ABI compare equal. By default, when this option is
not provided, only binaries with ABI changes are mentionned in the
output.
* ``--private-dso``
By default, ``abipkgdiff`` does not compare DSOs that are private
to the RPM package. A private DSO is a DSO which SONAME is *NOT*
advertised in the "provides" property of the RPM.
This option instructs ``abipkgdiff`` to *also* compare DSOs that
are *NOT* advertised in the "provides" property of the RPM.
Please note that the fact that (by default) ``abipkgdiff`` skips
private DSO is a feature that is available only for RPMs, at the
moment. We would happily accept patches adding that feature for
other package formats.
Note that this option is turned on by default, unless we are in
the presence of the `Linux Kernel`_.
* ``--redundant``
@@ -340,48 +541,36 @@ Options
change is a change that has been displayed elsewhere in a given
report.
* ``--harmless``
In the diff report, display only the :ref:`harmless
<harmlesschangeconcept_label>` changes. By default, the harmless
changes are filtered out of the diff report keep the clutter to a
minimum and have a greater chance to spot real ABI issues.
* ``--self-check``
* ``--no-linkage-name``
This is used to test the underlying Libabigail library. When in
used, the command expects only on input package, along with its
associated debug info packages. The command then compares each
binary inside the package against its own ABIXML
representation. The result of the comparison should yield the
empty set if Libabigail behaves correctly. Otherwise, it means
there is an issue that ought to be fixed. This option is used by
people interested in Libabigail development for regression testing
purposes. Here is an example of the use of this option: ::
In the resulting report, do not display the linkage names of
the added, removed, or changed functions or variables.
$ abipkgdiff --self-check --d1 mesa-libGLU-debuginfo-9.0.1-3.fc33.x86_64.rpm mesa-libGLU-9.0.1-3.fc33.x86_64.rpm
==== SELF CHECK SUCCEEDED for 'libGLU.so.1.3.1' ====
$
* ``--no-added-syms``
* ``--set1`` <package1-path> <package2-path> <package2-path> ...
Do not show the list of functions, variables, or any symbol that
was added.
Specifies the first set of packages whose binaries are to be
compared against the second one. Note that the second set of
packages is to be specified using the option ``--set2``.
* ``--no-added-binaries``
Do not show the list of binaries that got added to the second
package.
* ``--set2`` <package1-path> <package2-path> <package2-path> ...
Please note that the presence of such added binaries is not
considered like an ABI change by this tool; as such, it doesn't
have any impact on the exit code of the tool. It does only have
an informational value. Removed binaries are, however, considered
as an ABI change.
Specifies the second set of packages whose binaries are to be
compared against the second one. Note that the first set of
packages is to be specified using the option ``--set1``.
* ``--no-abignore``
Do not search the package for the presence of suppression files.
* ``--no-parallel``
By default, ``abipkgdiff`` will use all the processors it has available to
execute concurrently. This option tells it not to extract packages or run
comparisons in parallel.
* ``--no-default-suppression``
Do not load the :ref:`default suppression specification files
<abipkgdiff_default_supprs_label>`.
* ``--suppressions | --suppr`` <*path-to-suppressions*>
@@ -394,25 +583,11 @@ Options
the :ref:`default suppression specification files
<abipkgdiff_default_supprs_label>` are loaded .
* ``--linux-kernel-abi-whitelist | -w`` <*path-to-whitelist*>
When comparing two Linux kernel RPM packages, this option points
to the white list of names of ELF symbols of functions and
variables that must be compared for ABI changes. That white list
is called a "Linux kernel ABI white list".
* `--version | -v`
Any other function or variable which ELF symbol are not present in
that white list will not be considered by the ABI comparison
process.
Display the version of the program and exit.
If this option is not provided -- thus if no white list is
provided -- then the ABI of all publicly defined and exported
functions and global variables by the Linux Kernel binaries are
compared.
Please note that if a white list package is given in parameter,
this option handles it just fine, like if the --wp option was
used.
* ``--wp`` <*path-to-whitelist-package*>
@@ -444,120 +619,17 @@ Options
functions and global variables by the Linux Kernel binaries are
compared.
* ``--no-unreferenced-symbols``
In the resulting report, do not display change information about
function and variable symbols that are not referenced by any debug
information. Note that for these symbols not referenced by any
debug information, the change information displayed is either
added or removed symbols.
* ``--no-show-locs``
Do not show information about where in the *second shared library*
the respective type was changed.
* ``--show-bytes``
Show sizes and offsets in bytes, not bits. By default, sizes and
offsets are shown in bits.
* ``--show-bits``
Show sizes and offsets in bits, not bytes. This option is
activated by default.
* ``--show-hex``
Show sizes and offsets in hexadecimal base.
* ``--show-dec``
Show sizes and offsets in decimal base. This option is activated
by default.
* ``--no-show-relative-offset-changes``
Without this option, when the offset of a data member changes,
the change report not only mentions the older and newer offset,
but it also mentions by how many bits the data member changes.
With this option, the latter is not shown.
* ``--show-identical-binaries``
Show the names of the all binaries compared, including the
binaries whose ABI compare equal. By default, when this option is
not provided, only binaries with ABI changes are mentionned in the
output.
* ``--fail-no-dbg``
Make the program fail and return a non-zero exit code if couldn't
read any of the debug information that comes from the debug info
packages that were given on the command line. If no debug info
package were provided on the command line then this option is not
active.
Note that the non-zero exit code returned by the program as a
result of this option is the constant ``ABIDIFF_ERROR``. To know
the numerical value of that constant, please refer to the
:ref:`exit code documentation <abidiff_return_value_label>`.
* ``--keep-tmp-files``
Do not erase the temporary directory files that are created during
the execution of the tool.
* ``--verbose``
Emit verbose progress messages.
* ``--self-check``
* ``--verbose-diff``
This is used to test the underlying Libabigail library. When in
used, the command expects only on input package, along with its
associated debug info packages. The command then compares each
binary inside the package against its own ABIXML
representation. The result of the comparison should yield the
empty set if Libabigail behaves correctly. Otherwise, it means
there is an issue that ought to be fixed. This option is used by
people interested in Libabigail development for regression testing
purposes. Here is an example of the use of this option: ::
Emit timed verbose progress messages about the diffing process.
This option implies the --verbose one.
$ abipkgdiff --self-check --d1 mesa-libGLU-debuginfo-9.0.1-3.fc33.x86_64.rpm mesa-libGLU-9.0.1-3.fc33.x86_64.rpm
==== SELF CHECK SUCCEEDED for 'libGLU.so.1.3.1' ====
$
* ``--no-assume-odr-for-cplusplus``
When analysing a binary originating from C++ code using `DWARF`_
debug information, libabigail assumes the `One Definition Rule`_
to speed-up the analysis. In that case, when several types have
the same name in the binary, they are assumed to all be equal.
This option disables that assumption and instructs libabigail to
actually actually compare the types to determine if they are
equal.
* ``--no-leverage-dwarf-factorization``
When analysing a binary which `DWARF`_ debug information was
processed with the `DWZ`_ tool, the type information is supposed
to be already factorized. That context is used by libabigail to
perform some speed optimizations.
This option disables those optimizations.
* ``--ctf``
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:
+2 -1
View File
@@ -41,7 +41,7 @@ master_doc = 'index'
# General information about the project.
project = u'Libabigail'
copyright = u'2014-2022, Red Hat, Inc.'
copyright = u'2014-2025, Red Hat, Inc.'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -217,6 +217,7 @@ man_pages = [
('abidiff', 'abidiff', u'compare ABIs of ELF files ', [u'Dodji Seketeli'], 1),
('abipkgdiff', 'abipkgdiff', u'compare ABIs of ELF files in software packages ', [u'Dodji Seketeli'], 1),
('abidw', 'abidw', u'serialize the ABI of an ELF file', [u'Dodji Seketeli'], 1),
('abidb', 'abidb', u'check binary against abixml corpus and/or submit new data', [u'Frank Ch. Eigler'], 1),
('abilint', 'abilint', u'validate an abigail ABI representation', [u'Dodji Seketeli'], 1),
('abicompat', 'abicompat', u'check ABI compatibility', [u'Dodji Seketeli'], 1),
('fedabipkgdiff', 'fedabipkgdiff', u'compare ABIs of Fedora packages', [u'Chenxiong Qi'], 1),
+69 -45
View File
@@ -60,14 +60,33 @@ change reports that might be considered as false positives to users.
Options
=======
* ``--help | -h``
* ``--abipkgdiff`` <path/to/abipkgdiff>
Display a short help about the command and exit.
Specify an alternative abipkgdiff instead of the one installed in system.
* ``--dry-run``
Don't actually perform the ABI comparison. Details about what is
going to be done are emitted on standard output.
* ``--all-subpackages``
Instructs the tool to also compare the ABI of the binaries in the
sub-packages of the packages specified.
* ``--clean-cache``
If you want to clean cache both before and after ABI comparison,
``--clean-cache`` is the convenient way for you to save typing of two
options at same time.
* ``--clean-cache-after``
Clean cache after ABI comparison.
* ``--clean-cache-before``
Clean cache before ABI comparison.
* ``--debug``
@@ -75,20 +94,19 @@ Options
Details about each method invocation, including input parameters
and returned values, are emitted.
* ``--traceback``
Show traceback when an exception raised. This is useful for
developers of the tool itself to know more exceptional errors.
* ``--dry-run``
* ``--server`` <URL>
Don't actually perform the ABI comparison. Details about what is
going to be done are emitted on standard output.
Specifies the URL of the `Koji`_ XMLRPC service the tool talks to.
The default value of this option is http://koji.fedoraproject.org/kojihub.
* ``--topurl`` <URL>
* ``--dso-only``
Compares the ABI of shared libraries only. If this option is not
provided, the tool compares the ABI of all ELF binaries found in
the packages.
Specifies the URL of the package store the tool downloads RPMs
from. The default value of this option is https://kojipkgs.fedoraproject.org.
* ``--from`` <distro>
@@ -97,29 +115,10 @@ Options
``distro`` value can be any valid value of the RPM macro
``%{?dist}`` for `Fedora`_, for example, ``fc4``, ``fc23``, ``fc25``.
* ``--to`` <distro>
Specifies the name of the `Fedora`_ distribution in which to find
the `build`_ that is compared against the baseline specified by
option ``--from``. The ``distro`` value could be any valid value
of the RPM macro ``%{?dist}`` for `Fedora`_, for example, ``fc4``,
``fc23``.
* ``--help | -h``
* ``--all-subpackages``
Instructs the tool to also compare the ABI of the binaries in the
sub-packages of the packages specified.
* ``--dso-only``
Compares the ABI of shared libraries only. If this option is not
provided, the tool compares the ABI of all ELF binaries found in
the packages.
* ``--suppressions`` <*path-to-suppresions*>
Use a :ref:`suppression specification <suppr_spec_label>` file
located at *path-to-suppressions*.
Display a short help about the command and exit.
* ``--no-default-suppression``
@@ -127,6 +126,7 @@ Options
Do not load the :ref:`default suppression specification files
<fedabipkgdiff_default_supprs_label>`.
* ``--no-devel-pkg``
Do not take associated development packages into account when
@@ -137,6 +137,20 @@ Options
defined in public header files available from the packages being
compared.
* ``--private-dso``
Compare the ABI of shared libraries that are private to the
packages. If this option is not provided, shared libraries that
are private to the packages being considered are not compared.
* ``--server`` <URL>
Specifies the URL of the `Koji`_ XMLRPC service the tool talks to.
The default value of this option is http://koji.fedoraproject.org/kojihub.
* ``--show-identical-binaries``
Show the names of the all binaries compared, including the
@@ -144,23 +158,33 @@ Options
not provided, only binaries with ABI changes are mentionned in the
output.
* ``--abipkgdiff`` <path/to/abipkgdiff>
Specify an alternative abipkgdiff instead of the one installed in system.
* ``--suppressions`` <*path-to-suppresions*>
* ``--clean-cache-before``
Use a :ref:`suppression specification <suppr_spec_label>` file
located at *path-to-suppressions*.
Clean cache before ABI comparison.
* ``--clean-cache-after``
* ``--to`` <distro>
Clean cache after ABI comparison.
Specifies the name of the `Fedora`_ distribution in which to find
the `build`_ that is compared against the baseline specified by
option ``--from``. The ``distro`` value could be any valid value
of the RPM macro ``%{?dist}`` for `Fedora`_, for example, ``fc4``,
``fc23``.
* ``--clean-cache``
If you want to clean cache both before and after ABI comparison,
``--clean-cache`` is the convenient way for you to save typing of two
options at same time.
* ``--topurl`` <URL>
Specifies the URL of the package store the tool downloads RPMs
from. The default value of this option is https://kojipkgs.fedoraproject.org.
* ``--traceback``
Show traceback when an exception raised. This is useful for
developers of the tool itself to know more exceptional errors.
.. _build:
+3 -2
View File
@@ -7,8 +7,9 @@ Libabigail manual
=================
.. toctree::
:maxdepth: 2
:maxdepth: 3
libabigail-overview
libabigail-tools
libabigail-concepts
libabigail-tools
File diff suppressed because it is too large Load Diff
+1
View File
@@ -19,6 +19,7 @@ Tools manuals
abipkgdiff
kmidiff
abidw
abidb
abicompat
abilint
fedabipkgdiff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -27,7 +27,7 @@ DOXYFILE_ENCODING = UTF-8
# identify the project. Note that if you do not use Doxywizard you need
# to put quotes around the project name if it contains spaces.
PROJECT_NAME =
PROJECT_NAME = libabigail
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
+40 -7
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2022-2023 Red Hat, Inc.
// Copyright (C) 2022-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -18,15 +18,48 @@
namespace abigail
{
/// Namespace of the reader for the BTF debug information.
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);
/// 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<string>& debug_info_root_paths,
environment& env,
bool load_all_types = false,
bool linux_kernel_mode = false);
}//end namespace btf
}//end namespace abigail
+73 -3
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -25,12 +25,16 @@ namespace filtering
{
bool
has_harmless_name_change(const decl_base_sptr& f, const decl_base_sptr& s);
has_harmless_name_change(const decl_base_sptr& f,
const decl_base_sptr& s,
const diff_context_sptr& ctxt);
bool union_diff_has_harmless_changes(const diff *d);
bool
has_harmful_name_change(const decl_base_sptr& f, const decl_base_sptr& s);
has_harmful_name_change(const decl_base_sptr& f,
const decl_base_sptr& s,
const diff_context_sptr& ctxt);
bool
has_harmful_name_change(const diff* dif);
@@ -98,6 +102,72 @@ bool
is_var_1_dim_unknown_size_array_change(const var_decl_sptr& var1,
const var_decl_sptr& var2);
bool
has_strict_fam_conversion(const class_decl_sptr& first,
const class_decl_sptr& second);
bool
has_strict_fam_conversion(const diff *d);
bool
has_lvalue_reference_ness_change(const diff *d);
bool
has_void_ptr_to_ptr_change(const diff* d);
bool
has_void_to_non_void_change(const diff* d);
bool
has_void_to_non_void_change(const diff_sptr& d);
bool
has_harmless_enum_to_int_change(const diff* d);
bool
has_benign_array_of_unknown_size_change(const diff* dif);
diff_category
has_fn_return_or_parm_harmful_change(const diff* d);
diff_category
has_var_harmful_local_change(const diff* d);
diff_category
has_var_harmful_local_change(const diff_sptr& d);
bool
has_fn_with_virtual_offset_change(const diff* d);
bool
has_fn_with_virtual_offset_change(const diff_sptr& d);
bool
has_incompatible_fn_or_var_change(const diff* d);
bool
has_incompatible_fn_or_var_change(const diff_sptr& d);
bool
is_type_to_compatible_anonymous_type_change(const diff* d);
bool
is_type_to_compatible_anonymous_type_change(const diff_sptr& d);
bool
is_type_to_compatible_anonymous_type_change(const type_base_sptr&,
const type_base_sptr&);
bool
is_data_member_to_compatible_anonymous_dm_change(const diff* d);
bool
is_data_member_to_compatible_anonymous_dm_change(const diff_sptr& d);
bool
is_data_member_to_compatible_anonymous_dm_change(const decl_base_sptr&,
const decl_base_sptr&);
struct filter_base;
/// Convenience typedef for a shared pointer to filter_base
typedef shared_ptr<filter_base> filter_base_sptr;
+173 -29
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -120,10 +120,6 @@ typedef shared_ptr<class_diff> class_diff_sptr;
/// associated to the first one.
typedef unordered_map<size_t, size_t> pointer_map;
/// Convenience typedef for a map which key is a string and which
/// value is a @ref decl_base_sptr.
typedef unordered_map<string, decl_base_sptr> string_decl_base_sptr_map;
/// Convenience typedef for a map which key is a string and which
/// value is a @ref type_base_sptr.
typedef unordered_map<string, type_base_sptr> string_type_base_sptr_map;
@@ -204,7 +200,7 @@ typedef unordered_map<string, changed_enumerator> string_changed_enumerator_map;
/// Convenience typedef for a map which key is a string and which
/// value is a pointer to @ref decl_base.
typedef unordered_map<string, function_decl*> string_function_ptr_map;
typedef unordered_map<string, const function_decl*> string_function_ptr_map;
/// Convenience typedef for a map which key is a string and which
/// value is a @ref function_decl_diff_sptr.
@@ -229,7 +225,7 @@ typedef unordered_map<string, method_decl_sptr> string_member_function_sptr_map;
/// Convenience typedef for a map which key is a string and which
/// value is a point to @ref var_decl.
typedef unordered_map<string, var_decl*> string_var_ptr_map;
typedef unordered_map<string, var_decl_sptr> string_var_ptr_map;
/// Convenience typedef for a pair of pointer to @ref var_decl
/// representing a @ref var_decl change. The first member of the pair
@@ -357,8 +353,8 @@ enum diff_category
HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY = 1 << 6,
/// This means that a diff node in the sub-tree carries a harmless
/// union change.
HARMLESS_UNION_CHANGE_CATEGORY = 1 << 7,
/// union or class change.
HARMLESS_UNION_OR_CLASS_CHANGE_CATEGORY = 1 << 7,
/// This means that a diff node in the sub-tree carries a harmless
/// data member change. An example of harmless data member change
@@ -386,61 +382,69 @@ enum diff_category
/// incompatible change to a vtable.
VIRTUAL_MEMBER_CHANGE_CATEGORY = 1 << 12,
REFERENCE_LVALUENESS_CHANGE_CATEGORY = 1 << 13,
/// A change between two non-compatible types of different kinds.
NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY = 1 << 14,
/// A non-compatible name change between two types.
NON_COMPATIBLE_NAME_CHANGE_CATEGORY = 1 << 15,
/// A diff node in this category is redundant. That means it's
/// present as a child of a other nodes in the diff tree.
REDUNDANT_CATEGORY = 1 << 13,
REDUNDANT_CATEGORY = 1 << 16,
/// This means that a diff node in the sub-tree carries a type that
/// was declaration-only and that is now defined, or vice versa.
TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY = 1 << 14,
TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY = 1 << 17,
/// A diff node in this category is a function parameter type which
/// top cv-qualifiers change.
FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY = 1 << 15,
FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY = 1 << 18,
/// A diff node in this category has a function parameter type with a
/// cv-qualifiers change.
FN_PARM_TYPE_CV_CHANGE_CATEGORY = 1 << 16,
FN_PARM_TYPE_CV_CHANGE_CATEGORY = 1 << 19,
/// A diff node in this category is a function return type with a
/// cv-qualifier change.
FN_RETURN_TYPE_CV_CHANGE_CATEGORY = 1 << 17,
FN_RETURN_TYPE_CV_CHANGE_CATEGORY = 1 << 20,
/// A diff node in this category is a function (or function type)
/// with at least one parameter added or removed.
FN_PARM_ADD_REMOVE_CHANGE_CATEGORY = 1 << 18,
FN_PARM_ADD_REMOVE_CHANGE_CATEGORY = 1 << 21,
/// A diff node in this category is for a variable which type holds
/// a cv-qualifier change.
VAR_TYPE_CV_CHANGE_CATEGORY = 1 << 19,
VAR_TYPE_CV_CHANGE_CATEGORY = 1 << 22,
/// A diff node in this category carries a change from void pointer
/// to non-void pointer.
VOID_PTR_TO_PTR_CHANGE_CATEGORY = 1 << 20,
VOID_PTR_TO_PTR_CHANGE_CATEGORY = 1 << 23,
/// A diff node in this category carries a change in the size of the
/// array type of a global variable, but the ELF size of the
/// variable didn't change.
BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY = 1 << 21,
BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY = 1 << 24,
/// A diff node in this category carries a change that must be
/// reported, even if the diff node is also in the
/// SUPPRESSED_CATEGORY or PRIVATE_TYPE_CATEGORY categories.
/// Typically, this node matches a suppression specification like
/// the [allow_type] directive.
HAS_ALLOWED_CHANGE_CATEGORY = 1 << 22,
HAS_ALLOWED_CHANGE_CATEGORY = 1 << 25,
/// A diff node in this category has a descendant node that is in
/// the HAS_ALLOWED_CHANGE_CATEGORY category. Nodes in this
/// category must be reported, even if they are also in the
/// SUPPRESSED_CATEGORY or PRIVATE_TYPE_CATEGORY categories.
HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY = 1 << 23,
HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY = 1 << 26,
/// A diff node in this category has a parent node that is in the
/// HAS_ALLOWED_CHANGE_CATEGORY category. Nodes in this category
/// must be reported, even if they are also in the
/// SUPPRESSED_CATEGORY or PRIVATE_TYPE_CATEGORY categories.
HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY = 1 << 24,
HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY = 1 << 26,
/// A special enumerator that is the logical 'or' all the
/// enumerators above.
@@ -455,12 +459,15 @@ enum diff_category
| STATIC_DATA_MEMBER_CHANGE_CATEGORY
| HARMLESS_ENUM_CHANGE_CATEGORY
| HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY
| HARMLESS_UNION_CHANGE_CATEGORY
| HARMLESS_UNION_OR_CLASS_CHANGE_CATEGORY
| HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
| SUPPRESSED_CATEGORY
| PRIVATE_TYPE_CATEGORY
| SIZE_OR_OFFSET_CHANGE_CATEGORY
| VIRTUAL_MEMBER_CHANGE_CATEGORY
| REFERENCE_LVALUENESS_CHANGE_CATEGORY
| NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY
| NON_COMPATIBLE_NAME_CHANGE_CATEGORY
| REDUNDANT_CATEGORY
| TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
| FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
@@ -499,6 +506,9 @@ get_default_harmless_categories_bitmap();
diff_category
get_default_harmful_categories_bitmap();
bool
is_harmful_category(diff_category);
ostream&
operator<<(ostream& o, diff_category);
@@ -1086,6 +1096,9 @@ public:
bool
is_suppressed(bool &is_private_type) const;
bool
is_categorized_as_suppressed() const;
bool
to_be_reported() const;
@@ -1155,6 +1168,20 @@ compute_diff(const type_base_sptr,
const type_base_sptr,
diff_context_sptr ctxt);
/// Convert the type of a particular diff node into the generic @ref
/// diff_sptr type.
///
/// @tparam DiffNodePtr the specific type of the diff node to convert
/// into @ref diff_sptr
///
/// @param n the diff node to consider.
///
/// @return the instance of @ref diff_sptr @p n was converted into.
template <class DiffNodePtr>
diff_sptr
is_diff(DiffNodePtr& n)
{return std::dynamic_pointer_cast<diff>(n);}
/// The base class of diff between types.
class type_diff_base : public diff
{
@@ -1416,6 +1443,68 @@ compute_diff(reference_type_def_sptr first,
diff_context_sptr ctxt);
class ptr_to_mbr_diff;
/// Typedef of a shared_ptr to @ref ptr_to_mbr_diff
typedef shared_ptr<ptr_to_mbr_diff> ptr_to_mbr_diff_sptr;
/// The abstraction of a diff between two @ref ptr_to_mbr_type.
class ptr_to_mbr_diff : public type_diff_base
{
struct priv;
std::unique_ptr<priv> priv_;
ptr_to_mbr_diff() = default;
protected:
ptr_to_mbr_diff(const ptr_to_mbr_type_sptr& first,
const ptr_to_mbr_type_sptr& second,
const diff_sptr& member_type_diff,
const diff_sptr& containing_type_diff,
diff_context_sptr ctxt);
public:
ptr_to_mbr_type_sptr
first_ptr_to_mbr_type() const;
ptr_to_mbr_type_sptr
second_ptr_to_mbr_type() const;
const diff_sptr
member_type_diff() const;
const diff_sptr
containing_type_diff() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual const string&
get_pretty_representation() const;
virtual void
report(ostream&, const string& indent = "") const;
virtual void
chain_into_hierarchy();
virtual ~ptr_to_mbr_diff();
friend ptr_to_mbr_diff_sptr
compute_diff(const ptr_to_mbr_type_sptr& first,
const ptr_to_mbr_type_sptr& second,
diff_context_sptr& ctxt);
}; // end class ptr_to_mbr_diff
ptr_to_mbr_diff_sptr
compute_diff(const ptr_to_mbr_type_sptr& first,
const ptr_to_mbr_type_sptr& second,
diff_context_sptr& ctxt);
class subrange_diff;
/// A convenience typedef for a shared pointer to subrange_diff type.
@@ -1483,10 +1572,11 @@ class array_diff : public type_diff_base
std::unique_ptr<priv> priv_;
protected:
array_diff(const array_type_def_sptr first,
const array_type_def_sptr second,
diff_sptr element_type_diff,
diff_context_sptr ctxt = diff_context_sptr());
array_diff(const array_type_def_sptr first,
const array_type_def_sptr second,
diff_sptr element_type_diff,
vector<subrange_diff_sptr>& subrange_diffs,
diff_context_sptr ctxt = diff_context_sptr());
public:
const array_type_def_sptr
@@ -1498,9 +1588,18 @@ public:
const diff_sptr&
element_type_diff() const;
const vector<subrange_diff_sptr>&
subrange_diffs() const;
void
element_type_diff(diff_sptr);
void
subrange_diffs(const vector<subrange_diff_sptr>&);
bool
any_subrange_diff_to_be_reported() const;
virtual const string&
get_pretty_representation() const;
@@ -2456,10 +2555,16 @@ public:
added_functions();
const string_function_decl_diff_sptr_map&
changed_functions();
changed_functions() const;
const function_decl_diff_sptrs_type&
changed_functions_sorted();
changed_functions_sorted() const;
const function_decl_diff_sptrs_type&
incompatible_changed_functions() const;
function_decl_diff_sptrs_type&
incompatible_changed_functions();
const string_var_ptr_map&
deleted_variables() const;
@@ -2473,6 +2578,12 @@ public:
const var_diff_sptrs_type&
changed_variables_sorted();
const var_diff_sptrs_type&
incompatible_changed_variables() const;
var_diff_sptrs_type&
incompatible_changed_variables();
const string_elf_symbol_map&
deleted_unrefed_function_symbols() const;
@@ -2611,8 +2722,22 @@ public:
size_t num_func_with_virtual_offset_changes() const;
void num_func_with_virtual_offset_changes(size_t);
size_t num_func_with_local_harmful_changes() const;
void num_func_with_local_harmful_changes(size_t);
size_t num_func_with_incompatible_changes() const;
void num_func_with_incompatible_changes(size_t);
size_t num_var_with_local_harmful_changes() const;
void num_var_with_local_harmful_changes(size_t);
size_t num_var_with_incompatible_changes() const;
void num_var_with_incompatible_changes(size_t);
size_t net_num_func_changed() const;
size_t net_num_non_incompatible_func_changed() const;
size_t num_vars_removed() const;
void num_vars_removed(size_t);
@@ -2637,6 +2762,8 @@ public:
size_t net_num_vars_changed() const;
size_t net_num_non_incompatible_var_changed() const;
size_t num_func_syms_removed() const;
void num_func_syms_removed(size_t);
@@ -2685,16 +2812,24 @@ public:
size_t num_leaf_func_changes() const;
void num_leaf_func_changes(size_t);
size_t num_leaf_func_with_incompatible_changes() const;
void num_leaf_func_with_incompatible_changes(size_t);
size_t num_leaf_func_changes_filtered_out() const;
void num_leaf_func_changes_filtered_out(size_t);
size_t net_num_leaf_func_changes() const;
size_t net_num_leaf_func_non_incompatible_changes() const;
size_t num_leaf_var_changes() const;
void num_leaf_var_changes(size_t);
size_t num_leaf_var_with_incompatible_changes() const;
void num_leaf_var_with_incompatible_changes(size_t);
size_t num_leaf_var_changes_filtered_out() const;
void num_leaf_var_changes_filtered_out(size_t);
size_t net_num_leaf_var_changes() const;
size_t net_num_leaf_var_non_incompatible_changes() const;
size_t num_added_unreachable_types() const;
void num_added_unreachable_types(size_t);
@@ -2847,6 +2982,9 @@ void
print_diff_tree(corpus_diff_sptr diff_tree,
std::ostream&);
void
print_category(diff_category c);
void
categorize_redundancy(diff* diff_tree);
@@ -2872,7 +3010,10 @@ void
clear_redundancy_categorization(corpus_diff_sptr diff_tree);
void
apply_filters(corpus_diff_sptr diff_tree);
apply_filters_and_categorize_diff_node_tree(diff_sptr& diff_tree);
void
apply_filters_and_categorize_diff_node_tree(corpus_diff_sptr& c);
bool
is_diff_of_variadic_parameter_type(const diff*);
@@ -2922,6 +3063,9 @@ is_anonymous_class_or_union_diff(const diff* d);
const subrange_diff*
is_subrange_diff(const diff* diff);
const subrange_diff*
is_anonymous_subrange_diff(const diff* d);
const array_diff*
is_array_diff(const diff* diff);
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
+43 -8
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
@@ -28,10 +28,16 @@ public:
typedef vector<string> strings_type;
/// Convenience typedef for std::vector<abigail::ir::function_decl*>
typedef vector<function_decl*> functions;
typedef vector<const function_decl*> functions;
/// Convenience typedef for std::unordered_set<const function_decl*>
typedef std::unordered_set<const function_decl*> functions_set;
///Convenience typedef for std::vector<abigail::ir::var_decl*>
typedef vector<var_decl*> variables;
typedef vector<var_decl_sptr> variables;
/// Convenience typedef for std::unordered_set<const var_decl*>.
typedef std::unordered_set<var_decl_sptr> variables_set;
class exported_decls_builder;
@@ -219,7 +225,16 @@ public:
get_functions() const;
const std::unordered_set<function_decl*>*
lookup_functions(const string& id) const;
lookup_functions(const interned_string& id) const;
const std::unordered_set<function_decl*>*
lookup_functions(const char* id) const;
const std::unordered_set<var_decl_sptr>*
lookup_variables(const interned_string& id) const;
const std::unordered_set<var_decl_sptr>*
lookup_variables(const char* id) const;
void
sort_functions();
@@ -227,6 +242,24 @@ public:
virtual const variables&
get_variables() const;
const functions_set&
get_undefined_functions() const;
functions_set&
get_undefined_functions();
const functions&
get_sorted_undefined_functions() const;
const variables_set&
get_undefined_variables() const;
variables_set&
get_undefined_variables();
const variables&
get_sorted_undefined_variables() const;
void
sort_variables();
@@ -328,7 +361,7 @@ public:
exported_functions();
std::unordered_set<function_decl*>*
fn_id_maps_to_several_fns(function_decl*);
fn_id_maps_to_several_fns(const function_decl*);
const variables&
exported_variables() const;
@@ -336,11 +369,11 @@ public:
variables&
exported_variables();
void
bool
maybe_add_fn_to_exported_fns(function_decl*);
void
maybe_add_var_to_exported_vars(const var_decl*);
bool
maybe_add_var_to_exported_vars(const var_decl_sptr&);
}; //corpus::exported_decls_builder
/// Abstraction of a group of corpora.
@@ -414,6 +447,8 @@ public:
operator==(const corpus_group&) const;
}; // end class corpus_group
corpus_group_sptr
is_corpus_group(const corpus_sptr&);
}// end namespace ir
}//end namespace abigail
#endif //__ABG_CORPUS_H__
+5 -3
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2021-2023 Oracle, Inc.
// Copyright (C) 2021-2025 Oracle, Inc.
//
// Author: Jose E. Marchesi
@@ -23,18 +23,20 @@
namespace abigail
{
/// Namespace of the reader for the CTF debug information.
namespace ctf
{
elf_based_reader_sptr
create_reader(const std::string& elf_path,
const vector<char**>& debug_info_root_paths,
const vector<string>& debug_info_root_paths,
environment& env);
void
reset_reader(elf_based_reader& ctxt,
const std::string& elf_path,
const vector<char**>& debug_info_root_path);
const vector<string>& debug_info_root_path);
} // end namespace ctf_reader
} // end namespace abigail
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2019-2023 Google, Inc.
// Copyright (C) 2019-2025 Google, Inc.
/// @file
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
///
+4 -4
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -31,7 +31,7 @@ using namespace abigail::ir;
elf_based_reader_sptr
create_reader(const std::string& elf_path,
const vector<char**>& debug_info_root_paths,
const vector<string>& debug_info_root_paths,
environment& environment,
bool read_all_types = false,
bool linux_kernel_mode = false);
@@ -39,13 +39,13 @@ create_reader(const std::string& elf_path,
void
reset_reader(elf_based_reader& rdr,
const std::string& elf_path,
const vector<char**>& debug_info_root_paths,
const vector<string>& debug_info_root_paths,
bool read_all_types = false,
bool linux_kernel_mode = false);
corpus_sptr
read_corpus_from_elf(const std::string& elf_path,
const vector<char**>& debug_info_root_paths,
const vector<string>& debug_info_root_paths,
environment& environment,
bool load_all_types,
fe_iface::status& status);
+4 -4
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2022-2023 Red Hat, Inc.
// Copyright (C) 2022-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -43,7 +43,7 @@ protected:
/// method to create a reader instance as this constructor is
/// protected.
elf_based_reader(const std::string& elf_path,
const vector<char**>& debug_info_root_paths,
const vector<string>& debug_info_root_paths,
environment& env);
public:
@@ -51,7 +51,7 @@ public:
virtual void
initialize(const std::string& elf_path,
const vector<char**>& debug_info_root_paths);
const vector<string>& debug_info_root_paths);
virtual ir::corpus_sptr
read_and_add_corpus_to_group(ir::corpus_group& group,
@@ -59,7 +59,7 @@ public:
virtual void
initialize(const string& elf_path,
const vector<char**>& debug_info_root_paths,
const vector<string>& debug_info_root_paths,
bool load_all_types,
bool linux_kernel_mode) = 0;
+10 -4
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2022-2023 Red Hat, Inc.
// Copyright (C) 2022-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -67,19 +67,19 @@ class reader : public fe_iface
public:
reader(const std::string& elf_path,
const vector<char**>& debug_info_roots,
const vector<string>& debug_info_roots,
environment& env);
~reader();
virtual void
initialize(const std::string& elf_path,
const vector<char**>& debug_info_roots);
const vector<string>& debug_info_roots);
virtual void
initialize(const std::string& elf_path);
const vector<char**>&
const vector<string>&
debug_info_root_paths() const;
const Dwfl_Callbacks&
@@ -148,6 +148,12 @@ class reader : public fe_iface
elf_symbol_sptr
variable_symbol_is_exported(const string& name) const;
elf_symbol_sptr
function_symbol_is_undefined(const string& name) const;
elf_symbol_sptr
variable_symbol_is_undefined(const string& name) const;
void
load_dt_soname_and_needed();
+7 -3
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2022-2023 Red Hat, Inc.
// Copyright (C) 2022-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -61,6 +61,10 @@ protected:
environment& env;
bool load_in_linux_kernel_mode = false;
bool load_all_types = false;
/// If this option is set to true, then the functions and
/// variables that have an undefined symbol are going to be
/// represented in the IR.
bool load_undefined_interfaces = false;
bool drop_undefined_syms = false;
bool show_stats = false;
bool do_log = false;
@@ -138,10 +142,10 @@ protected:
should_reuse_type_from_corpus_group();
void
maybe_add_fn_to_exported_decls(const function_decl* fn);
add_fn_to_exported_or_undefined_decls(const function_decl* fn);
void
maybe_add_var_to_exported_decls(const var_decl* var);
add_var_to_exported_or_undefined_decls(const var_decl_sptr& var);
virtual ir::corpus_sptr
read_corpus(status& status) = 0;
+122 -38
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
@@ -22,7 +22,6 @@
#include <utility> // for std::rel_ops, at least.
#include <vector>
#include "abg-interned-str.h"
#include "abg-hash.h"
/// Toplevel namespace for libabigail.
namespace abigail
@@ -153,6 +152,10 @@ class decl_base;
// Convenience typedef for a smart pointer on @ref decl_base.
typedef shared_ptr<decl_base> decl_base_sptr;
/// Convenience typedef for a map which key is a string and which
/// value is a @ref decl_base_sptr.
typedef unordered_map<string, decl_base_sptr> string_decl_base_sptr_map;
class type_decl;
/// Convenience typedef for a shared pointer on a @ref type_decl.
typedef shared_ptr<type_decl> type_decl_sptr;
@@ -231,6 +234,10 @@ class reference_type_def;
/// Convenience typedef for a shared pointer on a @ref reference_type_def
typedef shared_ptr<reference_type_def> reference_type_def_sptr;
class ptr_to_mbr_type;
/// Convenience typedef for a shared pointer to a @ref ptr_to_mbr_type
typedef shared_ptr<ptr_to_mbr_type> ptr_to_mbr_type_sptr;
class array_type_def;
/// Convenience typedef for a shared pointer on a @ref array_type_def
@@ -251,10 +258,6 @@ typedef shared_ptr<var_decl> var_decl_sptr;
/// Convenience typedef for a weak pointer on a @ref var_decl
typedef weak_ptr<var_decl> var_decl_wptr;
typedef unordered_map<interned_string,
var_decl*,
hash_interned_string> istring_var_decl_ptr_map_type;
class scope_decl;
/// Convenience typedef for a shared pointer on a @ref scope_decl.
@@ -265,10 +268,6 @@ class function_decl;
/// Convenience typedef for a shared pointer on a @ref function_decl
typedef shared_ptr<function_decl> function_decl_sptr;
typedef unordered_map<interned_string,
function_decl*,
hash_interned_string> istring_function_decl_ptr_map_type;
class method_decl;
typedef shared_ptr<method_decl> method_decl_sptr;
@@ -359,13 +358,13 @@ const global_scope*
get_global_scope(const decl_base_sptr);
translation_unit*
get_translation_unit(const decl_base&);
get_translation_unit(const type_or_decl_base&);
translation_unit*
get_translation_unit(const decl_base*);
get_translation_unit(const type_or_decl_base*);
translation_unit*
get_translation_unit(const decl_base_sptr);
get_translation_unit(const type_or_decl_base_sptr&);
bool
is_global_scope(const scope_decl&);
@@ -436,6 +435,9 @@ is_anonymous_type(const type_base*);
bool
is_anonymous_type(const type_base_sptr&);
bool
is_npaf_type(const type_base_sptr&);
const type_decl*
is_type_decl(const type_or_decl_base*);
@@ -448,6 +450,12 @@ is_integral_type(const type_or_decl_base*);
type_decl_sptr
is_integral_type(const type_or_decl_base_sptr&);
type_decl*
is_real_type(const type_or_decl_base*);
type_decl_sptr
is_real_type(const type_or_decl_base_sptr&);
typedef_decl_sptr
is_typedef(const type_or_decl_base_sptr);
@@ -460,6 +468,9 @@ is_typedef(const type_base*);
typedef_decl*
is_typedef(type_base*);
const enum_type_decl*
is_compatible_with_enum_type(const type_base*);
enum_type_decl_sptr
is_compatible_with_enum_type(const type_base_sptr&);
@@ -490,6 +501,15 @@ has_flexible_array_data_member(const class_decl*);
var_decl_sptr
has_flexible_array_data_member(const class_decl_sptr&);
var_decl_sptr
has_fake_flexible_array_data_member(const class_decl&);
var_decl_sptr
has_fake_flexible_array_data_member(const class_decl*);
var_decl_sptr
has_fake_flexible_array_data_member(const class_decl_sptr&);
bool
is_declaration_only_class_or_union_type(const type_base *t,
bool look_through_decl_only = false);
@@ -521,32 +541,61 @@ is_union_type(const type_or_decl_base*);
union_decl_sptr
is_union_type(const type_or_decl_base_sptr&);
const class_decl*
is_compatible_with_class_type(const type_base*);
class_decl_sptr
is_compatible_with_class_type(const type_base_sptr&);
class_decl_sptr
is_compatible_with_class_type(const decl_base_sptr&);
pointer_type_def*
is_pointer_type(type_or_decl_base*);
const pointer_type_def*
is_pointer_type(const type_or_decl_base*);
is_pointer_type(const type_or_decl_base*,
bool look_through_qualifiers=false);
pointer_type_def_sptr
is_pointer_type(const type_or_decl_base_sptr&);
is_pointer_type(const type_or_decl_base_sptr&,
bool look_through_qualifiers=false);
pointer_type_def_sptr
is_pointer_to_function_type(const type_base_sptr&);
pointer_type_def_sptr
is_pointer_to_array_type(const type_base_sptr&);
pointer_type_def_sptr
is_pointer_to_ptr_to_mbr_type(const type_base_sptr&);
pointer_type_def_sptr
is_pointer_to_npaf_type(const type_base_sptr&);
bool
is_typedef_ptr_or_ref_to_decl_only_class_or_union_type(const type_base* t);
bool
is_typedef_of_maybe_qualified_class_or_union_type(const type_base* t);
bool
is_typedef_of_maybe_qualified_class_or_union_type(const type_base_sptr& t);
reference_type_def*
is_reference_type(type_or_decl_base*);
is_reference_type(type_or_decl_base*, bool look_through_qualifiers=false);
const reference_type_def*
is_reference_type(const type_or_decl_base*);
is_reference_type(const type_or_decl_base*, bool look_through_qualifiers=false);
reference_type_def_sptr
is_reference_type(const type_or_decl_base_sptr&);
is_reference_type(const type_or_decl_base_sptr&,
bool look_through_qualifiers=false);
const ptr_to_mbr_type*
is_ptr_to_mbr_type(const type_or_decl_base*,
bool look_through_qualifiers=false);
ptr_to_mbr_type_sptr
is_ptr_to_mbr_type(const type_or_decl_base_sptr&,
bool look_through_qualifiers=false);
const type_base*
is_void_pointer_type(const type_base*);
@@ -566,6 +615,15 @@ is_qualified_type(const type_or_decl_base*);
qualified_type_def_sptr
is_qualified_type(const type_or_decl_base_sptr&);
bool
is_const_qualified_type(const type_base_sptr& t);
bool
is_const_qualified_type(const qualified_type_def_sptr&);
type_base_sptr
peel_const_qualified_type(const qualified_type_def_sptr&);
function_type_sptr
is_function_type(const type_or_decl_base_sptr&);
@@ -608,6 +666,12 @@ look_through_decl_only(decl_base*);
decl_base_sptr
look_through_decl_only(const decl_base_sptr&);
type_base*
look_through_decl_only_type(type_base*);
type_base_sptr
look_through_decl_only_type(const type_base_sptr&);
var_decl*
is_var_decl(const type_or_decl_base*);
@@ -655,8 +719,8 @@ is_member_decl(const decl_base*);
bool
is_member_decl(const decl_base&);
scope_decl*
is_scope_decl(decl_base*);
const scope_decl*
is_scope_decl(const decl_base*);
scope_decl_sptr
is_scope_decl(const decl_base_sptr&);
@@ -724,6 +788,12 @@ get_last_data_member(const class_or_union*);
var_decl_sptr
get_last_data_member(const class_or_union_sptr&);
bool
collect_non_anonymous_data_members(const class_or_union* cou, string_decl_base_sptr_map& dms);
bool
collect_non_anonymous_data_members(const class_or_union_sptr &cou, string_decl_base_sptr_map& dms);
bool
is_anonymous_data_member(const decl_base&);
@@ -790,10 +860,12 @@ const class_or_union_sptr
data_member_has_anonymous_type(const var_decl_sptr& d);
array_type_def*
is_array_type(const type_or_decl_base* decl);
is_array_type(const type_or_decl_base* decl,
bool look_through_qualifiers = false);
array_type_def_sptr
is_array_type(const type_or_decl_base_sptr& decl);
is_array_type(const type_or_decl_base_sptr& decl,
bool look_through_qualifiers = false);
array_type_def_sptr
is_array_of_qualified_element(const type_base_sptr&);
@@ -895,14 +967,6 @@ get_member_function_vtable_offset(const function_decl&);
ssize_t
get_member_function_vtable_offset(const function_decl_sptr&);
void
set_member_function_vtable_offset(const function_decl& f,
ssize_t s);
void
set_member_function_vtable_offset(const function_decl_sptr &f,
ssize_t s);
bool
get_member_function_is_virtual(const function_decl&);
@@ -913,10 +977,11 @@ bool
get_member_function_is_virtual(const function_decl*);
void
set_member_function_is_virtual(function_decl&, bool);
set_member_function_virtuality(function_decl&, bool, ssize_t);
void
set_member_function_is_virtual(const function_decl_sptr&, bool);
set_member_function_virtuality(function_decl*, bool, ssize_t);
void
set_member_function_virtuality(const function_decl_sptr&, bool, ssize_t);
type_base_sptr
strip_typedef(const type_base_sptr);
@@ -1052,7 +1117,7 @@ interned_string
get_function_type_name(const function_type&, bool internal = false);
interned_string
get_function_id_or_pretty_representation(function_decl *fn);
get_function_id_or_pretty_representation(const function_decl *fn);
interned_string
get_method_type_name(const method_type_sptr&, bool internal = false);
@@ -1192,6 +1257,10 @@ get_type_declaration(type_base*);
decl_base_sptr
get_type_declaration(const type_base_sptr);
bool
classes_have_same_layout(const type_base_sptr& f,
const type_base_sptr& s);
bool
types_are_compatible(const type_base_sptr,
const type_base_sptr);
@@ -1517,7 +1586,7 @@ type_base_sptr
type_or_void(const type_base_sptr, const environment&);
type_base_sptr
canonicalize(type_base_sptr);
canonicalize(type_base_sptr type, bool do_log= false, bool show_stats= false);
type_base*
type_has_non_canonicalized_subtype(type_base_sptr t);
@@ -1588,6 +1657,21 @@ find_first_data_member_matching_regexp(const class_or_union& t,
var_decl_sptr
find_last_data_member_matching_regexp(const class_or_union& t,
const regex::regex_t_sptr& regex);
bool
decl_name_changed(const type_or_decl_base* a1, const type_or_decl_base *a2);
bool
decl_name_changed(const type_or_decl_base_sptr& d1,
const type_or_decl_base_sptr& d2);
bool
integral_type_has_harmless_name_change(const decl_base_sptr& f,
const decl_base_sptr& s);
bool
integral_type_has_harmless_name_change(const type_base_sptr& f,
const type_base_sptr& s);
} // end namespace ir
using namespace abigail::ir;
+269 -8
View File
@@ -1,30 +1,291 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
#ifndef __ABG_HASH_H__
#define __ABG_HASH_H__
#include <stdint.h>
#include <cstdint>
#include <cstddef>
#include <string>
#include "abg-ir.h"
namespace abigail
{
/// Namespace for hashing.
namespace hashing
{
/// Produce good hash value combining val1 and val2.
/// This is copied from tree.c in GCC.
std::size_t
combine_hashes(std::size_t, std::size_t);
uint32_t
fnv_hash(const std::string& str);
/// Enumeration of the different hashing states of an IR node being
/// hashed.
enum hashing_state
{
/// No hashing has been done/started.
HASHING_NOT_DONE_STATE = 0,
/// Hashing started but is not yet finished.
///
/// Note that when a type_or_decl_base::priv::set_hash_value is
/// invoked on an artifact which has this state, then the hash value
/// is set/saved onto the artifact.
HASHING_STARTED_STATE,
/// A cycle has been detected in the graph on the current node node.
///
/// This means the hashing has started on the current IR node and
/// while hashing its children nodes, this very same IR node is
/// visited again to be hashed. This is a cycle and it needs to be
/// broken otherwise the hashing continues forever.
///
/// Note that when a type_or_decl_base::priv::set_hash_value is
/// invoked on an artifact which has this state, then the hash value
/// is set/saved onto the artifact.
HASHING_CYCLED_TYPE_STATE,
/// Hashing a sub-type while hashing another type.
///
/// When a type_or_decl_base::hash_value() is invoked on an artifact
/// which has this state, it means the hash value that is computed
/// must NOT be set/saved onto the
/// artifact. type_or_decl_base::priv::set_hash_value is where this
/// is enforced.
HASHING_SUBTYPE_STATE,
/// Hashing of given IR node started and is now done. If an ABI
/// artifact is in this state, then it must have an hash value
/// available and should be get by peek_hash_value or
/// type_or_decl_base::hash_value().
HASHING_FINISHED_STATE,
};
bool
deserialize_hash(const string& input, uint64_t& hash);
bool
serialize_hash(uint64_t hash, string& output);
hash_t
combine_hashes(hash_t, hash_t);
uint32_t
fnv_hash(const std::string& str);
hash_t
hash(std::uint64_t v, std::uint64_t seed = 0);
hash_t
hash(const std::string& str);
hashing::hashing_state
get_hashing_state(const ir::type_or_decl_base& tod);
void
set_hashing_state(const ir::type_or_decl_base& tod,
hashing::hashing_state s);
bool
is_recursive_artefact(const type_or_decl_base& t);
void
is_recursive_artefact(const type_or_decl_base& t, bool f);
}//end namespace hashing
namespace ir
{
struct decl_base::hash
{
hash_t
operator()(const decl_base& d) const;
hash_t
operator()(const decl_base* d) const;
}; // end struct decl_base::hash
/// Hash functor for instances of @ref type_base.
struct type_base::hash
{
hash_t
operator()(const type_base& t) const;
hash_t
operator()(const type_base* t) const;
hash_t
operator()(const type_base_sptr t) const;
}; // end struct type_base::hash
/// Hash functor for instances of @ref type_decl.
struct type_decl::hash
{
hash_t
operator()(const type_decl& t) const;
hash_t
operator()(const type_decl* t) const;
}; // end struct type_decl::hash
/// Hash functor for instances of @ref qualified_type_def.
struct qualified_type_def::hash
{
hash_t
operator()(const qualified_type_def& t) const;
hash_t
operator()(const qualified_type_def* t) const;
}; // end struct qualified_type_def::hash
/// Hash functor for instances of @ref pointer_type_def.
struct pointer_type_def::hash
{
hash_t
operator()(const pointer_type_def& t) const;
hash_t
operator()(const pointer_type_def* t) const;
}; // end struct pointer_type_def::hash
/// Hash functor for instances of @ref reference_type_def.
struct reference_type_def::hash
{
hash_t
operator()(const reference_type_def& t) const;
hash_t
operator()(const reference_type_def* t) const;
}; // end struct reference_type_def::hash
/// Hash functor for instances of @ref ptr_to_mbr_type.
struct ptr_to_mbr_type::hash
{
hash_t
operator() (const ptr_to_mbr_type& t) const;
hash_t
operator() (const ptr_to_mbr_type* t) const;
hash_t
operator() (const ptr_to_mbr_type_sptr& t) const;
}; // end reference_type_def::hash
/// Hash functor for instances of @ref array_type_def::subrange_type
struct array_type_def::subrange_type::hash
{
hash_t
operator()(const array_type_def::subrange_type& s) const;
hash_t
operator()(const array_type_def::subrange_type* s) const;
};// end struct array_type_def::subrange_type::hash
/// Hash functor for instances of @ref array_type_def::hash
struct array_type_def::hash
{
hash_t
operator()(const array_type_def& t) const;
hash_t
operator()(const array_type_def* t) const;
}; //end struct array_type_def::hash
/// Hash functor for instances of @ref enum_type_decl
struct enum_type_decl::hash
{
hash_t
operator()(const enum_type_decl& t) const;
hash_t
operator()(const enum_type_decl* t) const;
};// end struct enum_type_decl::hash
/// Hash functor for instances of @ref typedef_decl
struct typedef_decl::hash
{
hash_t
operator()(const typedef_decl& t) const;
hash_t
operator()(const typedef_decl* t) const;
};// end struct typedef_decl::hash
/// The hashing functor for @ref function_type.
struct function_type::hash
{
hash_t
operator()(const function_type& t) const;
hash_t
operator()(const function_type* t) const;
hash_t
operator()(const function_type_sptr t) const;
};// end struct function_type::hash
/// Hashing functor for the @ref method_type type.
struct method_type::hash
{
hash_t
operator()(const method_type& t) const;
hash_t
operator()(const method_type* t) const;
hash_t
operator()(const method_type_sptr t) const;
}; // end struct method_type::hash
/// The hashing functor for member_base.
struct member_base::hash
{
hash_t
operator()(const member_base& m) const;
};
/// Hasher for the @ref class_or_union type
struct class_or_union::hash
{
hash_t
operator()(const class_or_union& t) const;
hash_t
operator()(const class_or_union* t) const;
}; // end struct class_decl::hash
/// The hashing functor for class_decl::base_spec.
struct class_decl::base_spec::hash
{
hash_t
operator()(const base_spec& t) const;
hash_t
operator()(const base_spec* t) const;
};
/// Hasher for the @ref class_decl type
struct class_decl::hash
{
hash_t
operator()(const class_decl& t) const;
hash_t
operator()(const class_decl* t) const;
}; // end struct class_decl::hash
/// Hash functor for instances of @ref union_decl type.
struct union_decl::hash
{
hash_t
operator()(const union_decl&) const;
hash_t
operator()(const union_decl*) const;
};//end struct union_decl::hash
}// end namespace ir
}//end namespace abigail
#endif //__ABG_HASH_H__
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2016-2023 Red Hat, Inc.
// Copyright (C) 2016-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
+277 -353
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
@@ -48,6 +48,7 @@ struct charDeleter
{ xmlFree(str); }
};
void initialize();
reader_sptr new_reader_from_file(const std::string& path);
reader_sptr new_reader_from_buffer(const std::string& buffer);
reader_sptr new_reader_from_istream(std::istream*);
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
///
+19 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2017-2023 Red Hat, Inc.
// Copyright (C) 2017-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -32,6 +32,7 @@ class qualified_type_diff;
class distinct_diff;
class pointer_diff;
class reference_diff;
class ptr_to_mbr_diff;
class subrange_diff;
class array_diff;
class base_diff;
@@ -89,6 +90,10 @@ public:
report(const reference_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const ptr_to_mbr_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const array_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
@@ -200,6 +205,15 @@ public:
report(const reference_diff& d, std::ostream& out,
const std::string& indent = "") const;
bool
report_local_ptr_to_mbr_type_changes(const ptr_to_mbr_diff& d,
std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const ptr_to_mbr_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const fn_parm_diff& d, std::ostream& out,
const std::string& indent = "") const;
@@ -291,6 +305,10 @@ public:
report(const reference_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const ptr_to_mbr_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const fn_parm_diff& d, std::ostream& out,
const std::string& indent = "") const;
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
///
+10 -4
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2016-2023 Red Hat, Inc.
// Copyright (C) 2016-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -336,6 +336,12 @@ public:
void
set_changed_enumerators_regexp(const vector<regex::regex_t_sptr>&);
bool
has_strict_fam_conversion () const;
void
set_has_strict_fam_conversion(bool);
virtual bool
suppresses_diff(const diff* diff) const;
@@ -943,13 +949,13 @@ suppression_matches_soname_or_filename(const string& soname,
const suppression_base& suppr);
const char*
get_private_types_suppr_spec_label();
get_opaque_types_suppr_spec_label();
bool
is_private_type_suppr_spec(const type_suppression&);
is_opaque_type_suppr_spec(const type_suppression&);
bool
is_private_type_suppr_spec(const suppression_sptr& s);
is_opaque_type_suppr_spec(const suppression_sptr& s);
bool
suppression_can_match(const fe_iface&,
+79 -7
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
///@file
@@ -40,11 +40,11 @@ const char* get_anonymous_subrange_internal_name_prefix();
bool file_exists(const string&);
bool is_regular_file(const string&);
bool file_has_dwarf_debug_info(const string& elf_file_path,
const vector<char**>& debug_info_root_paths);
const vector<string>& debug_info_root_paths);
bool file_has_ctf_debug_info(const string& elf_file_path,
const vector<char**>& debug_info_root_paths);
const vector<string>& debug_info_root_paths);
bool file_has_btf_debug_info(const string& elf_file_path,
const vector<char**>& debug_info_root_paths);
const vector<string>& debug_info_root_paths);
bool is_dir(const string&);
bool dir_exists(const string&);
bool dir_is_empty(const string &);
@@ -78,6 +78,8 @@ void get_comma_separated_args_of_option(const string& input_str,
bool get_dsos_provided_by_rpm(const string& rpm_path,
set<string>& provided_dsos);
string trim_white_space(const string&);
bool remove_white_spaces(string&);
bool normalize_litterals(string&);
string trim_leading_string(const string& from, const string& to_trim);
void convert_char_stars_to_char_star_stars(const vector<char*>&,
vector<char**>&);
@@ -97,6 +99,9 @@ suppr::suppressions_type
gen_suppr_spec_from_kernel_abi_whitelists
(const vector<string>& abi_whitelist_paths);
bool
get_file_path_dirs_under_dir(const string& root_dir, vector<string>& dirs);
bool
get_vmlinux_path_from_kernel_dist(const string& from,
string& vmlinux_path);
@@ -112,6 +117,9 @@ get_binary_paths_from_kernel_dist(const string& dist_root,
string& vmlinux_path,
vector<string>& module_paths);
bool
get_file_path_dirs_under_dir(const string& root, vector<string>& dirs);
string
get_default_system_suppression_file_path();
@@ -233,7 +241,22 @@ enum file_type
FILE_TYPE_DIR,
/// A tar archive. The archive can be compressed with the popular
/// compression schemes recognized by GNU tar.
FILE_TYPE_TAR
FILE_TYPE_TAR,
// All non-tared compression scheme go under here. When one of
// these is returned, the goal is to look into the uncompressed
// stream to get what format has been compressed, then return an
// enumerator for that compressed format instead.
//
// Please note that each time a new enumerator is added here, one
// needs to add a corresponding enumerator to the @ref
// compression_kind enum in abg-tools-utils.cc and update the
// is_compressed_file_type and get_compressed_streambuf functions
// accordingly.
/// The XZ (lzma) compresson scheme.
FILE_TYPE_XZ
};
/// Exit status for abidiff and abicompat tools.
@@ -322,7 +345,8 @@ operator<<(ostream& output, file_type r);
file_type guess_file_type(istream& in);
file_type guess_file_type(const string& file_path);
file_type guess_file_type(const string& file_path,
bool look_through_compression = true);
bool
get_rpm_name(const string& str, string& name);
@@ -348,6 +372,9 @@ file_is_kernel_debuginfo_package(const string& file_path,
std::shared_ptr<char>
make_path_absolute(const char*p);
string
make_path_absolute(const string& p);
char*
make_path_absolute_to_be_freed(const char*p);
@@ -364,12 +391,57 @@ build_corpus_group_from_kernel_dist_under(const string& root,
elf_based_reader_sptr
create_best_elf_based_reader(const string& elf_file_path,
const vector<char**>& debug_info_root_paths,
const vector<string>& debug_info_root_paths,
environment& env,
corpus::origin requested_debug_info_kind,
bool show_all_types,
bool linux_kernel_mode = false);
/// This is a custom std::streambuf that knows how to decompress an
/// input stream that was compressed using xz.
///
/// The code was inspired by the example in the source code of the xz
/// project at
/// https://github.com/tukaani-project/xz/blob/master/doc/examples/02_decompress.c.
///
/// here is an example of how a user code would use this custom
/// streambuf to decode an xz'ed file and emit its content to stdout.
///
/// ifstream input_file("/path/to/a/compressed/file.xz", ifstream::binary);
/// xz_decompressor_type xzed_streambuf(input_file);
/// istream input_stream(&xzed_streambuf);
///
/// const size_t BUFFER_SIZE = 1024 * 4;
/// vector<char> decompressed_data(BUFFER_SIZE);
/// input_stream.read(decompressed_data.data(), BUFFER_SIZE);
/// size_t nb_bytes_read = input_stream.gcount();
/// while (nb_bytes_read && !input_stream.bad())
/// {
/// for (auto c : decompressed_data)
/// std::out << c;
/// input_stream.read(decompressed_data.data(), BUFFER_SIZE);
/// nb_bytes_read = input_stream.gcount();
/// }
/// input_file.close();
///
/// Voila.
class xz_decompressor_type : public std::streambuf
{
struct priv;
std::unique_ptr<priv> priv_;
public:
xz_decompressor_type(std::istream& xz_istream);
~xz_decompressor_type();
protected:
int_type
underflow() override;
}; // end class xz_decompressor_type.
}// end namespace tools_utils
/// A macro that expands to aborting the program when executed.
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
+2 -2
View File
@@ -2,9 +2,9 @@
#ifndef __ABG_VERSION_H__
#define __ABG_VERSION_H__
#define ABIGAIL_VERSION_MAJOR "2"
#define ABIGAIL_VERSION_MINOR "4"
#define ABIGAIL_VERSION_MINOR "8"
#define ABIGAIL_VERSION_REVISION "0"
#define ABIGAIL_VERSION_SUFFIX ""
#define ABIGAIL_ABIXML_VERSION_MAJOR "2"
#define ABIGAIL_ABIXML_VERSION_MINOR "2"
#define ABIGAIL_ABIXML_VERSION_MINOR "4"
#endif
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
+5 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -57,6 +57,9 @@ set_write_comp_dir(write_context& ctxt, bool flag);
void
set_write_elf_needed(write_context& ctxt, bool flag);
void
set_write_undefined_symbols(write_context& ctxt, bool flag);
void
set_write_default_sizes(write_context& ctxt, bool flag);
@@ -88,6 +91,7 @@ set_common_options(write_context& ctxt, const OPTS& opts)
set_write_corpus_path(ctxt, opts.write_corpus_path);
set_write_comp_dir(ctxt, opts.write_comp_dir);
set_write_elf_needed(ctxt, opts.write_elf_needed);
set_write_undefined_symbols(ctxt, opts.load_undefined_interfaces);
set_write_parameter_names(ctxt, opts.write_parameter_names);
set_short_locs(ctxt, opts.short_locs);
set_write_default_sizes(ctxt, opts.default_sizes);
+6773
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -42,6 +42,7 @@ ohos_static_library("libabigail_static") {
"abg-tools-utils.cc",
"abg-traverse.cc",
"abg-writer.cc",
"xxhash.c",
]
include_dirs = [
+2 -2
View File
@@ -52,12 +52,12 @@ if BTF_READER
libabigail_la_SOURCES += abg-btf-reader.cc
endif
libabigail_la_LIBADD = $(DEPS_LIBS) $(FTS_LIBS)
libabigail_la_LIBADD = $(DEPS_LIBS)
libabigail_la_LDFLAGS = -lpthread -Wl,--as-needed -no-undefined -version-info $(LIBABIGAIL_SO_CURRENT):$(LIBABIGAIL_SO_REVISION):$(LIBABIGAIL_SO_AGE)
CUSTOM_MACROS = -DABIGAIL_ROOT_SYSTEM_LIBDIR=\"${libdir}\"
AM_CPPFLAGS=\
$(CUSTOM_MACROS) $(DEPS_CPPFLAGS) $(FTS_CFLAGS) \
$(CUSTOM_MACROS) $(DEPS_CPPFLAGS) \
-Wall -I$(abs_top_srcdir) -I$(abs_top_srcdir)/include \
-I$(abs_top_builddir)/include -I$(abs_top_builddir)
+320 -88
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2022-2023 Red Hat, Inc.
// Copyright (C) 2022-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -35,6 +35,7 @@ namespace abigail
{
using namespace ir;
/// Namespace of the reader for the BTF debug information.
namespace btf
{
@@ -52,33 +53,178 @@ btf_offset_to_string(const ::btf* btf, uint32_t offset)
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;
/// A convenience typedef of a map that associates a btf type to a
/// libabigail ABI artifact. The type is allocated inside a given btf
/// handle (of type ::btf*). All handles (one for each kernel binary)
/// should be kept around until a complete corpus group is built.
typedef std::unordered_map<const btf_type*, type_or_decl_base_sptr>
btf_type_to_abi_artifact_map_type;
/// The BTF front-end abstraction type.
///
/// Note that one instance of front-end is meant to analyze one
/// vmlinux file and all its associated modules. For now, the
/// front-end doesn't know how to analyze a module without having
/// analyzed a vmlinux first.
///
/// The BTF information of a vmlinux is parsed with the btf__parse
/// function. The result is called a "base BTF" handle.
///
/// The BTF information of a kernel module is parsed with the function
/// btf__parse_split. The result is called a "split BTF" handle. A
/// split BTF handle references information that are in the base BTF
/// handle. The base BTF handle can be retrieved from a split BTF
/// handle using btf__base_btf.
class reader : public elf_based_reader
{
::btf* btf_handle_ = nullptr;
::btf* base_btf_handle_ = nullptr;
// The path to the binary that contains the base BTF information
// held in base_btf_handle_
string base_btf_file_name_;
::btf* split_btf_handle_ = nullptr;
// The path to the binary that contains the split BTF information
// held in split_btf_handle_
string split_btf_file_name_;
// A vector of (split) BTF objects that are to be freed once the
// corpus group is built for an entire kernel (vmliunx + modules).
vector<::btf*> split_btfs_to_free_;
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_;
btf_type_to_abi_artifact_map_type btf_type_to_artifacts_;
/// Getter of the handle to the BTF data as returned by libbpf.
/// Getter of the "do_log" flag.
///
/// @return the handle to the BTF data as returned by libbpf.
/// This flag tells if we should log about various internal
/// details.
///
/// return the "do_log" flag.
bool
do_log() const
{return options().do_log;}
/// Setter of the "do_log" flag.
///
/// This flag tells if we should log about various internal details.
///
/// @param f the new value of the flag.
void
do_log(bool f)
{options().do_log = f;}
/// Getter of the "show_stats" flag.
///
/// This flag tells if we should emit statistics about various
/// internal stuff.
///
/// @return the value of the flag.
bool
show_stats() const
{return options().show_stats;}
/// Setter of the "show_stats" flag.
///
/// This flag tells if we should emit statistics about various
/// internal stuff.
///
/// @param f the value of the flag.
void
show_stats(bool f)
{options().show_stats = f;}
/// Getter of the handle to the base BTF object of the current
/// binary being analyzed.
///
/// The base BTF object ALWAYS represents the BTF information of the
/// vmlinux binary, even if the current binary being analyzed is a
/// kernel module.
///
/// @return handle to the base BTF object of the current binary
/// being analyzed.
::btf*
base_btf_handle()
{
if (base_btf_handle_ == nullptr)
{
base_btf_handle_ = btf__parse(corpus_path().c_str(), nullptr);
if (!base_btf_handle_)
{
std::cerr << "Could not parse base BTF information from file '"
<< corpus_path().c_str() << "'" << std::endl;
return nullptr;
}
base_btf_file_name_ = corpus_path();
}
return base_btf_handle_;
}
/// Read the BTF information of the current binary which path is
/// @ref fe_iface::corpus_path() and return its associated object
/// handle. This is called the split BTF object.
///
/// Note that this function expects the base BTF object (the one for
/// the vmlinux binary) to be already present, otherwise, it returns
/// nullptr.
///
/// @return the split BTF object for the file designed by
/// fe_iface::corpus_path().
::btf*
read_split_btf()
{
if (!base_btf_handle_)
{
std::cerr << "Base BTF information not present. "
<< "Not attempting to parse split BTF information"
<< std::endl;
return nullptr;
}
if (corpus_path().empty() || corpus_path() == base_btf_file_name_)
{
std::cerr << "BTF reader not initialized with split file name. "
<< "Not attending to read split BTF information"
<< std::endl;
return nullptr;
}
split_btf_handle_ = btf__parse_split(corpus_path().c_str(),
base_btf_handle());
if (!split_btf_handle_)
{
std::cerr << "Could not read split BTF information from file "
<< corpus_path() << std::endl;
return nullptr;
}
split_btf_file_name_ = corpus_path();
return split_btf_handle_;
}
/// Getter of the handle to the BTF object as returned by libbpf.
///
/// This returns the handle to the current BTF object. If the
/// current BTF object is for a vmlinux binary, then it's the base
/// BTF object that is returned. Otherwise, if the current BTF
/// object if for a kernel module then it's the split BTF object
/// that is returned.
///
/// @return the handle to the BTF object of the current binary being
/// analyeed by this front-end.
::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_;
if (split_btf_handle_)
return split_btf_handle_;
if (!base_btf_handle_)
return base_btf_handle();
if (corpus_path() != base_btf_file_name_)
// The reader was re-initialized with a corpus_path that is
// different from the the BTF base file. That means we are
// instructed to read a split BTF file information.
return read_split_btf();
return base_btf_handle();
}
/// Getter of the environment of the current front-end.
@@ -128,57 +274,60 @@ class reader : public elf_based_reader
cur_tu(const translation_unit_sptr& tu)
{cur_tu_ = tu;}
/// Getter of the map that associates a BTF type ID to an ABI
/// artifact.
/// Getter of the map that associates a BTF type to the internal
/// representation of an ABI artifact.
///
/// @return The map that associates a BTF type ID to an ABI
/// @return The map that associates a BTF type to the IR of an ABI
/// artifact.
btf_type_id_to_abi_artifact_map_type&
btf_type_id_to_artifacts()
{return btf_type_id_to_artifacts_;}
btf_type_to_abi_artifact_map_type&
btf_type_to_artifacts()
{return btf_type_to_artifacts_;}
/// Getter of the map that associates a BTF type ID to an ABI
/// Getter of the map that associates a BTF type to the IR of an ABI
/// artifact.
///
/// @return The map that associates a BTF type ID to an ABI
/// @return The map that associates a BTF type to the IR of an ABI
/// artifact.
const btf_type_id_to_abi_artifact_map_type&
btf_type_id_to_artifacts() const
{return btf_type_id_to_artifacts_;}
const btf_type_to_abi_artifact_map_type&
btf_type_to_artifacts() const
{return btf_type_to_artifacts_;}
/// Get the ABI artifact that is associated to a given BTF type ID.
/// Get the IR of the ABI artifact that is associated to a given BTF
/// type.
///
/// If no ABI artifact is associated to the BTF type id, then return
/// nil.
/// If no ABI artifact is associated to the BTF type, then return
/// nullptr.
///
/// @return the ABI artifact that is associated to a given BTF type
/// id.
/// @return the ABI artifact that is associated to a given BTF type.
type_or_decl_base_sptr
lookup_artifact_from_btf_id(int btf_id)
lookup_artifact_from_btf_type(const btf_type* t)
{
auto i = btf_type_id_to_artifacts().find(btf_id);
if (i != btf_type_id_to_artifacts().end())
auto i = btf_type_to_artifacts().find(t);
if (i != btf_type_to_artifacts().end())
return i->second;
return type_or_decl_base_sptr();
}
/// Associate an ABI artifact to a given BTF type ID.
/// Associate an ABI artifact to a given BTF type.
///
/// @param artifact the ABI artifact to consider.
///
/// @param btf_type_id the BTF type ID to associate to @p artifact.
/// @param btf_type_id the BTF type 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;}
associate_artifact_to_btf_type(const type_or_decl_base_sptr& artifact,
const btf_type* t)
{btf_type_to_artifacts()[t] = 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);}
schedule_type_for_canonicalization(const type_base_sptr& t)
{
if (t && !t->get_naked_canonical_type())
types_to_canonicalize_.push_back(t);
}
/// Canonicalize all the types scheduled for canonicalization using
/// abigail::ir::canonicalize_types() which performs some sanity
@@ -186,14 +335,41 @@ class reader : public elf_based_reader
void
canonicalize_types()
{
ir::canonicalize_types(types_to_canonicalize_.begin(),
types_to_canonicalize_.end(),
[](const vector<type_base_sptr>::const_iterator& i)
{return *i;});
tools_utils::timer cn_timer;
if (do_log())
{
std::cerr << "BTF Reader is going to canonicalize "
<< std::dec
<< types_to_canonicalize_.size()
<< " types";
corpus_sptr c = corpus();
if (c)
std::cerr << " from corpus " << corpus()->get_path() << "\n";
cn_timer.start();
}
ir::hash_and_canonicalize_types(types_to_canonicalize_.begin(),
types_to_canonicalize_.end(),
[](const vector<type_base_sptr>::const_iterator& i)
{return *i;}, do_log(), show_stats());
if (do_log())
{
cn_timer.stop();
std::cerr << "BTF Reader finished types "
<< "sorting, hashing & canonicalizing in: "
<< cn_timer << "\n";
}
}
/// Getter of the number of types carried by a given BTF object.
///
/// @param handle the BTF object to consider.
///
/// @return the number of types carried by a given BTF object.
uint64_t
nr_btf_types() const
nr_btf_types(const ::btf* handle) const
{
#ifdef WITH_BTF__GET_NR_TYPES
#define GET_NB_TYPES btf__get_nr_types
@@ -209,7 +385,7 @@ class reader : public elf_based_reader
return 0;
#endif
return GET_NB_TYPES(const_cast<reader*>(this)->btf_handle());
return GET_NB_TYPES(handle);
}
protected:
@@ -233,12 +409,25 @@ protected:
/// @param linux_kernel_mode
void
initialize(const string& elf_path,
const vector<char**>& debug_info_root_paths,
const vector<string>& debug_info_root_paths,
bool load_all_types,
bool linux_kernel_mode)
{
if (split_btf_handle_)
{
// We need to keep this split_btf_handle_ on the side so that
// we can free it when we are done analyzing all the kernel
// modules. We cannot free it right now because the memory of
// all btf types lives in it.
split_btfs_to_free_.push_back(split_btf_handle_);
split_btf_handle_ = nullptr;
}
split_btf_file_name_.clear();
types_to_canonicalize_.clear();
cur_tu_.reset();
elf_based_reader::initialize(elf_path, debug_info_root_paths);
btf__free(btf_handle_);
corpus_path(elf_path);
options().load_all_types = load_all_types;
options().load_in_linux_kernel_mode = linux_kernel_mode;
}
@@ -259,7 +448,7 @@ protected:
/// @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,
const vector<string>& debug_info_root_paths,
environment& environment,
bool load_all_types,
bool linux_kernel_mode)
@@ -290,7 +479,7 @@ public:
/// analyzed as a linux kernel binary.
static btf::reader_sptr
create(const string& elf_path,
const vector<char**>& debug_info_root_paths,
const vector<string>& debug_info_root_paths,
environment& environment,
bool load_all_types,
bool linux_kernel_mode)
@@ -303,7 +492,12 @@ public:
/// Destructor of the btf::reader type.
~reader()
{
btf__free(btf_handle_);
for (auto b : split_btfs_to_free_)
btf__free(b);
btf__free(split_btf_handle_);
btf__free(base_btf_handle_);
split_btf_handle_ = nullptr;
base_btf_handle_ = nullptr;
}
/// Read the ELF information as well as the BTF type information to
@@ -321,6 +515,11 @@ public:
corpus::origin origin = corpus()->get_origin();
origin |= corpus::BTF_ORIGIN;
corpus()->set_origin(origin);
if (corpus_group())
{
origin |= corpus_group()->get_origin();
corpus_group()->set_origin(origin);
}
if ((status & STATUS_NO_SYMBOLS_FOUND)
|| !(status & STATUS_OK))
@@ -345,15 +544,43 @@ public:
corpus_sptr
read_debug_info_into_corpus()
{
btf_handle();
if (!btf_handle())
return corpus_sptr();
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();
#ifdef WITH_DEBUG_SELF_COMPARISON
if (env().self_comparison_debug_is_on())
{
corpus_group_sptr g = corpus_group();
if (g)
env().set_self_comparison_debug_input(g);
else
env().set_self_comparison_debug_input(corpus());
}
#endif
int number_of_types = nr_btf_types(btf_handle());
int first_type_id = 1;
// Are we looking at the BTF for a kernel module?
const ::btf* base = btf__base_btf(btf_handle());
if (base)
{
// So, base is non-nil. This means we are looking at the BTF
// for a kernel module and base points to the BTF for the
// corresponding vmlinux. That base BTF should be the same as
// base_btf_handle().
ABG_ASSERT(base == base_btf_handle());
// The ID of the first type that is contained in this BTF
// representing a kernel module is the number of types
// contained in the base BTF (i.e, the BTF for the vmlinux
// binary).
first_type_id = nr_btf_types(base);
}
// Let's cycle through whatever is described in the BTF section
// and emit libabigail IR for it.
@@ -397,7 +624,8 @@ public:
}
canonicalize_types();
corpus()->sort_functions();
corpus()->sort_variables();
return corpus();
}
@@ -413,13 +641,10 @@ public:
type_or_decl_base_sptr result;
const btf_type *t = nullptr;
if ((result = lookup_artifact_from_btf_id(type_id)))
return result;
t = btf__type_by_id(btf_handle(), type_id);
if (type_id == 0)
result = build_ir_node_for_void_type();
else
t = btf__type_by_id(btf_handle(), type_id);
if ((result = lookup_artifact_from_btf_type(t)))
return result;
if (!result)
{
@@ -428,6 +653,11 @@ public:
switch(type_kind)
{
case BTF_KIND_UNKN/* Unknown: This is really for the void
type. */:
result = build_ir_node_for_void_type();
break;
case BTF_KIND_INT/* Integer */:
result = build_int_type(type_id);
break;
@@ -484,12 +714,14 @@ public:
#ifdef WITH_BTF_KIND_TYPE_TAG
case BTF_KIND_TYPE_TAG/* Type Tag */:
break;
#endif
#ifdef WITH_BTF_KIND_DECL_TAG
case BTF_KIND_DECL_TAG/* Decl Tag */:
break;
#endif
case BTF_KIND_DATASEC/* Section */:
case BTF_KIND_UNKN/* Unknown */:
break;
default:
ABG_ASSERT_NOT_REACHED;
break;
@@ -499,20 +731,14 @@ public:
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);
schedule_type_for_canonicalization(type);
associate_artifact_to_btf_type_id(result, type_id);
associate_artifact_to_btf_type(result, t);
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());
}
add_fn_to_exported_or_undefined_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());
}
add_var_to_exported_or_undefined_decls(var);
return result;
}
@@ -525,7 +751,7 @@ public:
{
type_base_sptr t = env().get_void_type();
add_decl_to_scope(is_decl(t), cur_tu()->get_global_scope());
canonicalize(t);
schedule_type_for_canonicalization(t);
return t;
}
@@ -537,7 +763,7 @@ public:
{
type_base_sptr t = env().get_void_pointer_type();
add_decl_to_scope(is_decl(t), cur_tu()->get_global_scope());
canonicalize(t);
schedule_type_for_canonicalization(t);
return t;
}
@@ -550,7 +776,7 @@ public:
type_base_sptr t = env().get_variadic_parameter_type();
add_decl_to_scope(is_decl(t), cur_tu()->get_global_scope());
decl_base_sptr t_decl = get_type_declaration(t);
canonicalize(t);
schedule_type_for_canonicalization(t);
return t;
}
@@ -643,7 +869,7 @@ public:
result->set_is_anonymous(is_anonymous);
result->set_is_artificial(true);
add_decl_to_scope(result, cur_tu()->get_global_scope());
canonicalize(result);
schedule_type_for_canonicalization(result);
return result;
}
@@ -789,16 +1015,18 @@ public:
if (!underlying_type)
return type_or_decl_base_sptr();
uint64_t lower_boud = 0;
uint64_t lower_bound = 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,
lower_bound, upper_bound,
location()));
subrange->is_non_finite(!arr->nelems);
subrange->set_size_in_bits(cur_tu()->get_address_size());
add_decl_to_scope(subrange, cur_tu()->get_global_scope());
canonicalize(subrange);
schedule_type_for_canonicalization(subrange);
array_type_def::subranges_type subranges = {subrange};
array_type_def_sptr result(new array_type_def(underlying_type,
subranges, location()));
@@ -892,7 +1120,7 @@ public:
add_decl_to_scope(result, cur_tu()->get_global_scope());
associate_artifact_to_btf_type_id(result, type_id);
associate_artifact_to_btf_type(result, t);
// For defined classes and unions, add data members to the type
// being built.
@@ -955,7 +1183,7 @@ public:
/*alignment=*/0));
result->set_return_type(return_type);
associate_artifact_to_btf_type_id(result, type_id);
associate_artifact_to_btf_type(result, t);
uint16_t nb_parms = btf_vlen(t);
const struct btf_param* parm =
@@ -1020,10 +1248,12 @@ public:
location(), /*linkage_name=*/fn_name));
elf_symbol_sptr fn_sym;
if ((fn_sym = function_symbol_is_exported(fn_name)))
if ((fn_sym = function_symbol_is_exported(fn_name))
|| (fn_sym = function_symbol_is_undefined(fn_name)))
{
result->set_symbol(fn_sym);
result->set_is_in_public_symbol_table(true);
if (fn_sym->is_defined())
result->set_is_in_public_symbol_table(true);
}
return result;
}
@@ -1054,10 +1284,12 @@ public:
/*linkage_name=*/var_name));
elf_symbol_sptr var_sym;
if ((var_sym = variable_symbol_is_exported(var_name)))
if ((var_sym = variable_symbol_is_exported(var_name))
|| (var_sym = variable_symbol_is_undefined(var_name)))
{
result->set_symbol(var_sym);
result->set_is_in_public_symbol_table(true);
if (var_sym->is_defined())
result->set_is_in_public_symbol_table(true);
}
return result;
}
@@ -1098,7 +1330,7 @@ public:
/// @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,
const vector<string>& debug_info_root_paths,
environment& env,
bool load_all_types,
bool linux_kernel_mode)
+1243 -166
View File
File diff suppressed because it is too large Load Diff
+67 -41
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2017-2023 Red Hat, Inc.
// Copyright (C) 2017-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -59,7 +59,7 @@ struct types_or_decls_hash
{
size_t h1 = hash_type_or_decl(d.first);
size_t h2 = hash_type_or_decl(d.second);
return hashing::combine_hashes(h1, h2);
return *hashing::combine_hashes(hash_t(h1), hash_t(h2));
}
};
@@ -429,9 +429,12 @@ struct array_diff::priv
{
/// The diff between the two array element types.
diff_sptr element_type_diff_;
vector<subrange_diff_sptr> subrange_diffs_;
priv(diff_sptr element_type_diff)
: element_type_diff_(element_type_diff)
priv(diff_sptr element_type_diff,
vector<subrange_diff_sptr>& subrange_diffs)
: element_type_diff_(element_type_diff),
subrange_diffs_(subrange_diffs)
{}
};//end struct array_diff::priv
@@ -443,6 +446,19 @@ struct reference_diff::priv
{}
};//end struct reference_diff::priv
/// The private data of the @ref ptr_to_mbr_diff type.
struct ptr_to_mbr_diff::priv
{
diff_sptr member_type_diff_;
diff_sptr containing_type_diff_;
priv(const diff_sptr& member_type_diff,
const diff_sptr& containing_type_diff)
: member_type_diff_(member_type_diff),
containing_type_diff_(containing_type_diff)
{}
};//end ptr_to_mbr_diff::priv
struct qualified_type_diff::priv
{
diff_sptr underlying_type_diff;
@@ -698,6 +714,13 @@ struct base_diff_comp
{return operator()(l.get(), r.get());}
}; // end struct base_diff_comp
bool
is_less_than(const decl_diff_base& first, const decl_diff_base& second);
bool
is_less_than(const decl_diff_base_sptr& first,
const decl_diff_base_sptr& second);
/// A comparison functor to compare two instances of @ref var_diff
/// that represent changed data members based on the offset of the
/// initial data members, or if equal, based on their qualified name.
@@ -759,7 +782,7 @@ struct data_member_diff_comp
return name1 < name2;
}
}; // end struct var_diff_comp
}; // end struct data_member_diff_comp
/// A comparison functor for instances of @ref function_decl_diff that
/// represent changes between two virtual member functions.
@@ -772,8 +795,12 @@ struct virtual_member_function_diff_comp
ABG_ASSERT(get_member_function_is_virtual(l.first_function_decl()));
ABG_ASSERT(get_member_function_is_virtual(r.first_function_decl()));
return (get_member_function_vtable_offset(l.first_function_decl())
< get_member_function_vtable_offset(r.first_function_decl()));
size_t l_offset = get_member_function_vtable_offset(l.first_function_decl());
size_t r_offset = get_member_function_vtable_offset(r.first_function_decl());
if (l_offset != r_offset)
return l_offset < r_offset;
return is_less_than(l, r);
}
bool
@@ -858,9 +885,9 @@ struct diff_comp
bool
operator()(const diff& l, diff& r) const
{
return (get_pretty_representation(l.first_subject(), true)
return (get_pretty_representation(l.first_subject())
<
get_pretty_representation(r.first_subject(), true));
get_pretty_representation(r.first_subject()));
}
/// Lexicographically compare two diff nodes.
@@ -990,6 +1017,10 @@ struct var_comp
bool
operator() (const var_decl* l, const var_decl* r) const
{return operator()(*l, *r);}
bool
operator() (const var_decl_sptr& l, const var_decl_sptr& r) const
{return operator()(l.get(), r.get());}
};// end struct var_comp
/// A functor to compare instances of @ref elf_symbol base on their
@@ -1052,11 +1083,13 @@ struct corpus_diff::priv
string_function_ptr_map suppressed_added_fns_;
string_function_decl_diff_sptr_map changed_fns_map_;
function_decl_diff_sptrs_type changed_fns_;
function_decl_diff_sptrs_type incompatible_changed_fns_;
string_var_ptr_map deleted_vars_;
string_var_ptr_map suppressed_deleted_vars_;
string_var_ptr_map added_vars_;
string_var_ptr_map suppressed_added_vars_;
string_var_diff_sptr_map changed_vars_map_;
var_diff_sptrs_type incompatible_changed_vars_;
var_diff_sptrs_type sorted_changed_vars_;
string_elf_symbol_map added_unrefed_fn_syms_;
string_elf_symbol_map suppressed_added_unrefed_fn_syms_;
@@ -1124,10 +1157,10 @@ struct corpus_diff::priv
added_function_is_suppressed(const function_decl* fn) const;
bool
deleted_variable_is_suppressed(const var_decl* var) const;
deleted_variable_is_suppressed(const var_decl_sptr& var) const;
bool
added_variable_is_suppressed(const var_decl* var) const;
added_variable_is_suppressed(const var_decl_sptr& var) const;
bool
added_unreachable_type_is_suppressed(const type_base *t)const ;
@@ -1244,30 +1277,7 @@ struct function_decl_diff_comp
operator()(const function_decl_diff& first,
const function_decl_diff& second)
{
function_decl_sptr f = first.first_function_decl(),
s = second.first_function_decl();
string fr = f->get_qualified_name(),
sr = s->get_qualified_name();
if (fr == sr)
{
if (f->get_symbol())
fr = f->get_symbol()->get_id_string();
else if (!f->get_linkage_name().empty())
fr = f->get_linkage_name();
else
fr = f->get_pretty_representation();
if (s->get_symbol())
sr = s->get_symbol()->get_id_string();
else if (!s->get_linkage_name().empty())
sr = s->get_linkage_name();
else
sr = s->get_pretty_representation();
}
return (fr.compare(sr) < 0);
return is_less_than(first, second);
}
/// The actual less than operator.
@@ -1298,11 +1308,9 @@ struct var_diff_sptr_comp
///
/// @return true if @p f is less than @p s.
bool
operator()(const var_diff_sptr f,
const var_diff_sptr s)
operator()(const var_diff_sptr f, const var_diff_sptr s)
{
return (f->first_var()->get_qualified_name()
< s->first_var()->get_qualified_name());
return is_less_than(f, s);
}
}; // end struct var_diff_sptr_comp
@@ -1319,6 +1327,10 @@ struct corpus_diff::diff_stats::priv
size_t num_func_changed;
size_t num_changed_func_filtered_out;
size_t num_func_with_virt_offset_changes;
size_t num_func_with_local_harmful_changes;
size_t num_func_with_incompatible_changes;
size_t num_var_with_local_harmful_changes;
size_t num_var_with_incompatible_changes;
size_t num_vars_removed;
size_t num_removed_vars_filtered_out;
size_t num_vars_added;
@@ -1338,8 +1350,10 @@ struct corpus_diff::diff_stats::priv
size_t num_leaf_type_changes;
size_t num_leaf_type_changes_filtered_out;
size_t num_leaf_func_changes;
size_t num_leaf_func_with_incompatible_changes;
size_t num_leaf_func_changes_filtered_out;
size_t num_leaf_var_changes;
size_t num_leaf_var_with_incompatible_changes;
size_t num_leaf_var_changes_filtered_out;
size_t num_added_unreachable_types;
size_t num_added_unreachable_types_filtered_out;
@@ -1357,6 +1371,10 @@ struct corpus_diff::diff_stats::priv
num_func_changed(),
num_changed_func_filtered_out(),
num_func_with_virt_offset_changes(),
num_func_with_local_harmful_changes(),
num_func_with_incompatible_changes(),
num_var_with_local_harmful_changes(),
num_var_with_incompatible_changes(),
num_vars_removed(),
num_removed_vars_filtered_out(),
num_vars_added(),
@@ -1376,8 +1394,10 @@ struct corpus_diff::diff_stats::priv
num_leaf_type_changes(),
num_leaf_type_changes_filtered_out(),
num_leaf_func_changes(),
num_leaf_func_with_incompatible_changes(),
num_leaf_func_changes_filtered_out(),
num_leaf_var_changes(),
num_leaf_var_with_incompatible_changes(),
num_leaf_var_changes_filtered_out(),
num_added_unreachable_types(),
num_added_unreachable_types_filtered_out(),
@@ -1409,7 +1429,7 @@ sort_changed_data_members(changed_var_sptrs_type& input);
void
sort_string_function_ptr_map(const string_function_ptr_map& map,
vector<function_decl*>& sorted);
vector<const function_decl*>& sorted);
void
sort_string_member_function_sptr_map(const string_member_function_sptr_map& map,
@@ -1424,17 +1444,23 @@ sort_string_function_decl_diff_sptr_map
(const string_function_decl_diff_sptr_map& map,
function_decl_diff_sptrs_type& sorted);
void
sort_function_decl_diffs(function_decl_diff_sptrs_type& fn_diffs);
void
sort_string_var_diff_sptr_map(const string_var_diff_sptr_map& map,
var_diff_sptrs_type& sorted);
void
sort_var_diffs(var_diff_sptrs_type& var_diffs);
void
sort_string_elf_symbol_map(const string_elf_symbol_map& map,
vector<elf_symbol_sptr>& sorted);
void
sort_string_var_ptr_map(const string_var_ptr_map& map,
vector<var_decl*>& sorted);
vector<var_decl_sptr>& sorted);
void
sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map& map,
+1027 -87
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
+171 -60
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2016-2023 Red Hat, Inc.
// Copyright (C) 2016-2025 Red Hat, Inc.
/// @file
///
@@ -19,6 +19,7 @@
#include "abg-regex.h"
#include "abg-sptr-utils.h"
#include "abg-symtab-reader.h"
#include "abg-interned-str.h"
namespace abigail
{
@@ -46,9 +47,27 @@ typedef unordered_map<string, vector<function_decl*> > str_fn_ptrs_map_type;
typedef unordered_map<string, std::unordered_set<function_decl*> >
str_fn_ptr_set_map_type;
/// Convenience typedef for a hash map which key is an interned_string
/// and which data is a set of abigail::ir::function_decl*
typedef unordered_map<interned_string,
std::unordered_set<function_decl*>,
hash_interned_string> istr_fn_ptr_set_map_type;
/// Convenience typedef for a hash map which key is a string and
/// which data is an abigail::ir::var_decl*.
typedef unordered_map<string, var_decl*> str_var_ptr_map_type;
typedef unordered_map<string, var_decl_sptr> str_var_ptr_map_type;
/// Convenience typedef for a hash map which key is an interned_string
/// and which data is an abigail::ir::var_decl*.
typedef unordered_map<interned_string,
var_decl_sptr,
hash_interned_string> istr_var_ptr_map_type;
/// Convenience typedef for a hash map which key is an interned_string
/// and which data is a set of abigail::ir::var_decl_sptr
typedef unordered_map<interned_string,
std::unordered_set<var_decl_sptr>,
hash_interned_string> istr_var_ptr_set_map_type;
/// The type of the private data of @ref
/// corpus::exported_decls_builder type.
@@ -62,15 +81,15 @@ class corpus::exported_decls_builder::priv
functions& fns_;
variables& vars_;
// A map that associates a function ID (function symbol and its
// version) to to a vector of functions with that ID. Normally, one
// version) to a vector of functions with that ID. Normally, one
// would think that in the corpus, there must only one function for
// a given ID. Actually, in c++, there can be two function template
// instantiations that produce the same function ID because the
// template parameters of the second instantiation are just typedefs
// of the first instantiation, for instance. So there can be cases
// where one ID appertains to more than one function.
str_fn_ptr_set_map_type id_fns_map_;
str_var_ptr_map_type id_var_map_;
istr_fn_ptr_set_map_type id_fns_map_;
istr_var_ptr_set_map_type id_vars_map_;
strings_type& fns_suppress_regexps_;
regex_t_sptrs_type compiled_fns_suppress_regexp_;
strings_type& vars_suppress_regexps_;
@@ -203,48 +222,45 @@ public:
///
/// @return a map which key is a string and which data is a pointer
/// to a function.
const str_fn_ptr_set_map_type&
const istr_fn_ptr_set_map_type&
id_fns_map() const
{return id_fns_map_;}
/// Getter for a map of the IDs of the functions that are present in
/// the set of exported functions.
///
/// This map is useful during the construction of the set of
/// exported functions, at least to ensure that every function is
/// present only once in that set.
/// The map associates the ID of a function with the set of
/// functions having the symbol that matches the ID.
///
/// @return a map which key is a string and which data is a pointer
/// to a function.
str_fn_ptr_set_map_type&
/// @return a map which key is a string and which data is a set of
/// functions.
istr_fn_ptr_set_map_type&
id_fns_map()
{return id_fns_map_;}
/// Getter for a map of the IDs of the variables that are present in
/// the set of exported variables.
///
/// This map is useful during the construction of the set of
/// exported variables, at least to ensure that every function is
/// present only once in that set.
/// The map associates the ID of a variable with the set of variables
/// having the symbol that matches the ID.
///
/// @return a map which key is a string and which data is a pointer
/// to a function.
const str_var_ptr_map_type&
id_var_map() const
{return id_var_map_;}
/// @return a map which key is a string and which data is a set of
/// variables.
istr_var_ptr_set_map_type&
id_vars_map()
{return id_vars_map_;}
/// Getter for a map of the IDs of the variables that are present in
/// the set of exported variables.
///
/// This map is useful during the construction of the set of
/// exported variables, at least to ensure that every function is
/// present only once in that set.
/// The map associates the ID of a variable with the set of variables
/// having the symbol that matches the ID.
///
/// @return a map which key is a string and which data is a pointer
/// to a function.
str_var_ptr_map_type&
id_var_map()
{return id_var_map_;}
/// @return a map which key is a string and which data is a set of
/// variables.
const istr_var_ptr_set_map_type&
id_vars_map() const
{return id_vars_map_;}
/// Returns an ID for a given function.
///
@@ -274,10 +290,10 @@ public:
/// @return the pointer to the vector of functions with ID @p fn_id,
/// or nil if no function with that ID exists.
std::unordered_set<function_decl*>*
fn_id_is_in_id_fns_map(const string& fn_id)
fn_id_is_in_id_fns_map(const interned_string& fn_id)
{
str_fn_ptr_set_map_type& m = id_fns_map();
str_fn_ptr_set_map_type::iterator i = m.find(fn_id);
istr_fn_ptr_set_map_type& m = id_fns_map();
auto i = m.find(fn_id);
if (i == m.end())
return 0;
return &i->second;
@@ -295,7 +311,7 @@ public:
std::unordered_set<function_decl*>*
fn_id_is_in_id_fns_map(const function_decl* fn)
{
string fn_id = fn->get_id();
interned_string fn_id = fn->get_id();
return fn_id_is_in_id_fns_map(fn_id);
}
@@ -389,7 +405,7 @@ public:
return;
// First associate the function id to the function.
string fn_id = fn->get_id();
interned_string fn_id = fn->get_id();
std::unordered_set<function_decl*>* fns = fn_id_is_in_id_fns_map(fn_id);
if (!fns)
fns = &(id_fns_map()[fn_id] = std::unordered_set<function_decl*>());
@@ -415,34 +431,123 @@ public:
while (sym && !sym->is_main_symbol());
}
/// Test if a given (ID of a) varialble is present in the variable
/// Test if a given (ID of a) variable is present in the variable
/// map. In other words, it tests if a given variable is present in
/// the set of exported variables.
///
/// @param fn_id the ID of the variable to consider.
///
/// @return true iff the variable designated by @p fn_id is present
/// in the set of exported variables.
bool
var_id_is_in_id_var_map(const string& var_id) const
/// @return a pointer to the set of variables that have the same ID
/// as @p var_id.
std::unordered_set<var_decl_sptr>*
var_id_is_in_id_vars_map(const interned_string& var_id)
{
const str_var_ptr_map_type& m = id_var_map();
str_var_ptr_map_type::const_iterator i = m.find(var_id);
return i != m.end();
istr_var_ptr_set_map_type& m = id_vars_map();
auto i = m.find(var_id);
if (i != m.end())
return &i->second;
return nullptr;
}
/// Add a given variable to the map of functions that are present in
/// the set of exported functions.
/// Test if a given (ID of a) variable is present in the variable
/// map. In other words, it tests if a given variable is present in
/// the set of exported variables.
///
/// @param id the variable to add to the map.
void
add_var_to_map(var_decl* var)
/// @param fn_id the ID of the variable to consider.
///
/// @return a pointer to the set of variables that have the same ID
/// as @p var_id.
const std::unordered_set<var_decl_sptr>*
var_id_is_in_id_vars_map(const interned_string& var_id) const
{
if (var)
return const_cast<corpus::exported_decls_builder::priv*>(this)->
var_id_is_in_id_vars_map(var_id);
}
/// Test if a given variable is present in a set of variables.
///
/// The variable compares the ID and the qualified name of
/// variables.
///
/// @param fn the variable to consider.
///
/// @parm fns the set of variables to consider.
static bool
var_is_in_vars(const var_decl_sptr& var,
const std::unordered_set<var_decl_sptr>& vars)
{
if (vars.empty())
return false;
if (vars.find(var) != vars.end())
return true;
const string var_id = var->get_id();
for (const auto& v: vars)
if (v->get_id() == var_id
&& v->get_qualified_name() == var->get_qualified_name())
return true;
return false;
}
/// Test if a given variable is present in a set of variables.
///
/// The variable compares the ID and the qualified name of
/// variables.
///
/// @param fn the variable to consider.
///
/// @parm fns the set of variables to consider.
bool
var_is_in_id_vars_map(const var_decl_sptr& var)
{
if (!var)
return false;
interned_string var_id = var->get_id();
const std::unordered_set<var_decl_sptr>* vars =
var_id_is_in_id_vars_map(var_id);
if (vars && var_is_in_vars(var, *vars))
return true;
return false;
}
/// Add a given variable to the map of variables that are present in
/// the set of exported variables.
///
/// @param fn the variable to add to the map.
void
add_var_to_id_vars_map(const var_decl_sptr& var)
{
if (!var)
return;
// First associate the var id to the variable.
interned_string var_id = var->get_id();
std::unordered_set<var_decl_sptr>* vars = var_id_is_in_id_vars_map(var_id);
if (!vars)
vars = &(id_vars_map()[var_id] = std::unordered_set<var_decl_sptr>());
vars->insert(var);
// Now associate all aliases of th underlying symbol to the
// variable too.
elf_symbol_sptr sym = var->get_symbol();
ABG_ASSERT(sym);
string sym_id;
do
{
const string& var_id = get_id(*var);
id_var_map()[var_id] = var;
sym_id = sym->get_id_string();
if (sym_id == var_id)
goto loop;
vars = var_id_is_in_id_vars_map(var_id);
if (!vars)
vars = &(id_vars_map()[var_id] = std::unordered_set<var_decl_sptr>());
vars->insert(var);
loop:
sym = sym->get_next_alias();
}
while (sym && !sym->is_main_symbol());
}
/// Add a function to the set of exported functions.
@@ -462,13 +567,12 @@ public:
///
/// @param fn the variable to add to the set of exported variables.
void
add_var_to_exported(const var_decl* var)
add_var_to_exported(const var_decl_sptr& var)
{
const string& id = get_id(*var);
if (!var_id_is_in_id_var_map(id))
if (!var_is_in_id_vars_map(var))
{
vars_.push_back(const_cast<var_decl*>(var));
add_var_to_map(const_cast<var_decl*>(var));
vars_.push_back(var);
add_var_to_id_vars_map(var);
}
}
@@ -604,7 +708,7 @@ public:
///
/// @return true iff the variable is to be kept.
bool
keep_wrt_id_of_vars_to_keep(const var_decl* var)
keep_wrt_id_of_vars_to_keep(const var_decl_sptr& var)
{
if (!var)
return false;
@@ -649,7 +753,7 @@ public:
///
/// @return true iff the variable is to be kept.
bool
keep_wrt_regex_of_vars_to_suppress(const var_decl *var)
keep_wrt_regex_of_vars_to_suppress(const var_decl_sptr var)
{
if (!var)
return false;
@@ -678,7 +782,7 @@ public:
///
/// @return true iff the variable is to be kept.
bool
keep_wrt_regex_of_vars_to_keep(const var_decl *var)
keep_wrt_regex_of_vars_to_keep(const var_decl_sptr& var)
{
if (!var)
return false;
@@ -729,8 +833,12 @@ struct corpus::priv
string architecture_name;
translation_units members;
string_tu_map_type path_tu_map;
vector<function_decl*> fns;
vector<var_decl*> vars;
vector<const function_decl*> fns;
vector<var_decl_sptr> vars;
functions_set undefined_fns;
functions sorted_undefined_fns;
variables_set undefined_vars;
variables sorted_undefined_vars;
symtab_reader::symtab_sptr symtab_;
// The type maps contained in this data member are populated if the
// corpus follows the One Definition Rule and thus if there is only
@@ -747,7 +855,7 @@ struct corpus::priv
type_maps type_per_loc_map_;
mutable vector<type_base_wptr> types_not_reachable_from_pub_ifaces_;
unordered_set<interned_string, hash_interned_string> *pub_type_pretty_reprs_;
bool do_log;
bool do_log;
private:
priv();
@@ -813,6 +921,9 @@ public:
unordered_set<interned_string, hash_interned_string>*
get_public_types_pretty_representations();
std::unordered_set<function_decl*>*
lookup_functions(const interned_string& id);
~priv();
}; // end struct corpus::priv
+230 -49
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
@@ -14,6 +14,7 @@
#include <stdexcept>
#include <unordered_map>
#include <set>
#include <memory>
#include "abg-internal.h"
@@ -122,7 +123,7 @@ corpus::exported_decls_builder::exported_functions()
/// @return the set of functions designated by the ELF symbol of @p
/// fn, or nullptr if the function ID maps to just @p fn.
std::unordered_set<function_decl*>*
corpus::exported_decls_builder::fn_id_maps_to_several_fns(function_decl* fn)
corpus::exported_decls_builder::fn_id_maps_to_several_fns(const function_decl* fn)
{
std::unordered_set<function_decl*> *fns_for_id =
priv_->fn_id_is_in_id_fns_map(fn);
@@ -155,22 +156,29 @@ corpus::exported_decls_builder::exported_variables()
/// the function to that set.
///
/// @param fn the function to add the set of exported functions.
void
///
/// @return true iff the function was added to the set of exported
/// functions.
bool
corpus::exported_decls_builder::maybe_add_fn_to_exported_fns(function_decl* fn)
{
if (!fn->get_is_in_public_symbol_table())
return;
return false;
const string& fn_id = priv_->get_id(*fn);
ABG_ASSERT(!fn_id.empty());
if (priv_->fn_is_in_id_fns_map(fn))
return;
return false;
if (priv_->keep_wrt_id_of_fns_to_keep(fn)
&& priv_->keep_wrt_regex_of_fns_to_suppress(fn)
&& priv_->keep_wrt_regex_of_fns_to_keep(fn))
priv_->add_fn_to_exported(fn);
{
priv_->add_fn_to_exported(fn);
return true;
}
return false;
}
/// Consider at all the tunables that control wether a variable should
@@ -178,22 +186,29 @@ corpus::exported_decls_builder::maybe_add_fn_to_exported_fns(function_decl* fn)
/// the variable to that set.
///
/// @param fn the variable to add the set of exported variables.
void
corpus::exported_decls_builder::maybe_add_var_to_exported_vars(const var_decl* var)
///
/// @return true iff the variable was added to the set of exported
/// variables.
bool
corpus::exported_decls_builder::maybe_add_var_to_exported_vars(const var_decl_sptr& var)
{
if (!var->get_is_in_public_symbol_table())
return;
return false;
const string& var_id = priv_->get_id(*var);
const interned_string& var_id = priv_->get_id(*var);
ABG_ASSERT(!var_id.empty());
if (priv_->var_id_is_in_id_var_map(var_id))
return;
if (priv_->var_is_in_id_vars_map(var))
return false;
if (priv_->keep_wrt_id_of_vars_to_keep(var)
&& priv_->keep_wrt_regex_of_vars_to_suppress(var)
&& priv_->keep_wrt_regex_of_vars_to_keep(var))
priv_->add_var_to_exported(var);
{
priv_->add_var_to_exported(var);
return true;
}
return false;
}
// </corpus::exported_decls_builder>
@@ -293,8 +308,12 @@ struct var_comp
return first_name < second_name;
}
};
bool
operator()(const var_decl_sptr& first,
const var_decl_sptr& second) const
{return operator()(first.get(), second.get());}
};
/// A comparison functor to compare elf_symbols for the purpose of
/// sorting.
@@ -630,6 +649,34 @@ corpus::priv::get_public_types_pretty_representations()
return pub_type_pretty_reprs_;
}
/// Lookup the function which has a given function ID.
///
/// Note that there can have been several functions with the same ID.
/// This is because debug info can declare the same function in
/// several different translation units. Normally, all these function
/// should be equal. But still, this function returns all these
/// functions.
///
/// @param id the ID of the function to lookup. This ID must be
/// either the result of invoking function::get_id() of
/// elf_symbol::get_id_string().
///
/// @return the set of functions which ID is @p id, or nil if no
/// function with that ID was found.
std::unordered_set<function_decl*>*
corpus::priv::lookup_functions(const interned_string& id)
{
exported_decls_builder_sptr &b = exported_decls_builder;
if (b)
{
auto i = b->priv_->id_fns_map_.find(id);
if (i == b->priv_->id_fns_map_.end())
return 0;
return &i->second;
}
return nullptr;
}
/// Destructor of the @ref corpus::priv type.
corpus::priv::~priv()
{
@@ -682,14 +729,11 @@ corpus::add(const translation_unit_sptr& tu)
{
ABG_ASSERT(priv_->members.insert(tu).second);
if (!tu->get_absolute_path().empty())
{
// Update the path -> translation_unit map.
string_tu_map_type::const_iterator i =
priv_->path_tu_map.find(tu->get_absolute_path());
ABG_ASSERT(i == priv_->path_tu_map.end());
priv_->path_tu_map[tu->get_absolute_path()] = tu;
}
// Update the path -> translation_unit map.
string_tu_map_type::const_iterator i =
priv_->path_tu_map.find(tu->get_absolute_path());
ABG_ASSERT(i == priv_->path_tu_map.end());
priv_->path_tu_map[tu->get_absolute_path()] = tu;
tu->set_corpus(this);
}
@@ -1166,13 +1210,16 @@ corpus::get_undefined_var_symbol_map() const
const elf_symbol_sptr
corpus::lookup_function_symbol(const string& n) const
{
if (get_fun_symbol_map().empty())
if (get_fun_symbol_map().empty() && get_undefined_fun_symbol_map().empty())
return elf_symbol_sptr();
string_elf_symbols_map_type::const_iterator it =
get_fun_symbol_map().find(n);
string_elf_symbols_map_type::const_iterator it = get_fun_symbol_map().find(n);
if ( it == get_fun_symbol_map().end())
return elf_symbol_sptr();
{
it = get_undefined_fun_symbol_map().find(n);
if (it == get_undefined_fun_symbol_map().end())
return elf_symbol_sptr();
}
return it->second[0];
}
@@ -1233,13 +1280,17 @@ const elf_symbol_sptr
corpus::lookup_function_symbol(const string& symbol_name,
const elf_symbol::version& version) const
{
if (get_fun_symbol_map().empty())
if (get_fun_symbol_map().empty() && get_undefined_fun_symbol_map().empty())
return elf_symbol_sptr();
string_elf_symbols_map_type::const_iterator it =
get_fun_symbol_map().find(symbol_name);
if ( it == get_fun_symbol_map().end())
return elf_symbol_sptr();
{
it = get_undefined_fun_symbol_map().find(symbol_name);
if (it == get_undefined_fun_symbol_map().end())
return elf_symbol_sptr();
}
return find_symbol_by_version(version, it->second);
}
@@ -1262,13 +1313,16 @@ corpus::lookup_function_symbol(const elf_symbol& symbol) const
const elf_symbol_sptr
corpus::lookup_variable_symbol(const string& n) const
{
if (get_var_symbol_map().empty())
if (get_var_symbol_map().empty() && get_undefined_var_symbol_map().empty())
return elf_symbol_sptr();
string_elf_symbols_map_type::const_iterator it =
get_var_symbol_map().find(n);
string_elf_symbols_map_type::const_iterator it = get_var_symbol_map().find(n);
if ( it == get_var_symbol_map().end())
return elf_symbol_sptr();
{
it = get_undefined_var_symbol_map().find(n);
if (it == get_undefined_var_symbol_map().end())
return elf_symbol_sptr();
}
return it->second[0];
}
@@ -1284,13 +1338,17 @@ const elf_symbol_sptr
corpus::lookup_variable_symbol(const string& symbol_name,
const elf_symbol::version& version) const
{
if (get_var_symbol_map().empty())
if (get_var_symbol_map().empty() && get_undefined_var_symbol_map().empty())
return elf_symbol_sptr();
string_elf_symbols_map_type::const_iterator it =
get_var_symbol_map().find(symbol_name);
if ( it == get_var_symbol_map().end())
return elf_symbol_sptr();
{
it = get_undefined_var_symbol_map().find(symbol_name);
if (it == get_undefined_var_symbol_map().end())
return elf_symbol_sptr();
}
return find_symbol_by_version(version, it->second);
}
@@ -1335,18 +1393,54 @@ corpus::get_functions() const
/// either the result of invoking function::get_id() of
/// elf_symbol::get_id_string().
///
/// @return the vector functions which ID is @p id, or nil if no
/// @return the set of functions which ID is @p id, or nil if no
/// function with that ID was found.
const std::unordered_set<function_decl*>*
corpus::lookup_functions(const string& id) const
corpus::lookup_functions(const interned_string& id) const
{return priv_->lookup_functions(id);}
const std::unordered_set<function_decl*>*
corpus::lookup_functions(const char* id) const
{
if (!id)
return nullptr;
interned_string string_id = priv_->env.intern(id);
return lookup_functions(string_id);
}
/// Lookup the exported variables which all have a given variable ID.
///
/// @param id the ID of the variable to look up.
///
/// @return a pointer to the set of variables with ID @p id, or
/// nullptr if no variable was found with that ID.
const std::unordered_set<var_decl_sptr>*
corpus::lookup_variables(const interned_string& id) const
{
exported_decls_builder_sptr b = get_exported_decls_builder();
auto i = b->priv_->id_fns_map_.find(id);
if (i == b->priv_->id_fns_map_.end())
return 0;
auto i = b->priv_->id_vars_map_.find(id);
if (i == b->priv_->id_vars_map_.end())
return nullptr;
return &i->second;
}
/// Lookup the exported variables which all have a given variable ID.
///
/// @param id the ID of the variable to look up.
///
/// @return a pointer to the set of variables with ID @p id, or
/// nullptr if no variable was found with that ID.
const std::unordered_set<var_decl_sptr>*
corpus::lookup_variables(const char* id) const
{
if (!id)
return nullptr;
interned_string string_id = priv_->env.intern(id);
return lookup_variables(string_id);
}
/// Sort the set of functions exported by this corpus.
///
/// Normally, you shouldn't be calling this as the code that creates
@@ -1356,6 +1450,14 @@ corpus::sort_functions()
{
func_comp fc;
std::sort(priv_->fns.begin(), priv_->fns.end(), fc);
priv_->sorted_undefined_fns.clear();
for (auto& f : priv_->undefined_fns)
priv_->sorted_undefined_fns.push_back(f);
std::sort(priv_->sorted_undefined_fns.begin(),
priv_->sorted_undefined_fns.end(), fc);
}
/// Return the public decl table of the global variables of the
@@ -1386,6 +1488,79 @@ corpus::sort_variables()
{
var_comp vc;
std::sort(priv_->vars.begin(), priv_->vars.end(), vc);
priv_->sorted_undefined_vars.clear();
for (auto& f : priv_->undefined_vars)
priv_->sorted_undefined_vars.push_back(f);
std::sort(priv_->sorted_undefined_vars.begin(),
priv_->sorted_undefined_vars.end(), vc);
}
/// Getter of the undefined functions of the corpus.
///
/// Undefined functions are functions which symbols are not defined.
///
/// @return a set of @ref function_decl* representing the functions
/// that are undefined in the corpus.
const corpus::functions_set&
corpus::get_undefined_functions() const
{return priv_->undefined_fns;}
/// Getter of the undefined functions of the corpus.
///
/// @return a set of @ref function_decl* representing the functions
/// that are undefined in the corpus.
corpus::functions_set&
corpus::get_undefined_functions()
{return priv_->undefined_fns;}
/// Getter of the sorted vector of undefined functions of the corpus.
///
/// @return a vector of @ref function_decl* representing the functions
/// that are undefined in the corpus.
const corpus::functions&
corpus::get_sorted_undefined_functions() const
{
if (priv_->sorted_undefined_fns.empty()
&& !priv_->undefined_fns.empty())
// We have undefined functions but we haven't sorted them yet.
// Let's do the sorting now then.
const_cast<corpus*>(this)->sort_functions();
return priv_->sorted_undefined_fns;
}
/// Getter of the undefined variables of the corpus.
///
/// @return a set of @ref var_decl* representing the variables that
/// are undefined in the corpus.
const corpus::variables_set&
corpus::get_undefined_variables() const
{return priv_->undefined_vars;}
/// Getter of the undefined variables of the corpus.
///
/// @return a set of @ref var_decl* representing the variables that
/// are undefined in the corpus.
corpus::variables_set&
corpus::get_undefined_variables()
{return priv_->undefined_vars;}
/// Getter of the sorted vector of undefined variables of the corpus.
///
/// @return a sorted vector of @ref var_decl* representing the
/// variables that are undefined in the corpus.
const corpus::variables&
corpus::get_sorted_undefined_variables() const
{
if (priv_->sorted_undefined_vars.empty()
&& !priv_->undefined_vars.empty())
// We have undefined variables but we haven't sorted them yet.
// Let's do the sorting now then.
const_cast<corpus*>(this)->sort_variables();
return priv_->sorted_undefined_vars;
}
/// Getter of the set of function symbols that are not referenced by
@@ -1538,11 +1713,9 @@ corpus::maybe_drop_some_exported_decls()
{
string sym_name, sym_version;
vector<function_decl*> fns_to_keep;
functions fns_to_keep;
exported_decls_builder* b = get_exported_decls_builder().get();
for (vector<function_decl*>::iterator f = priv_->fns.begin();
f != priv_->fns.end();
++f)
for (auto f = priv_->fns.begin(); f != priv_->fns.end(); ++f)
{
if (b->priv_->keep_wrt_id_of_fns_to_keep(*f)
&& b->priv_->keep_wrt_regex_of_fns_to_suppress(*f)
@@ -1551,10 +1724,8 @@ corpus::maybe_drop_some_exported_decls()
}
priv_->fns = fns_to_keep;
vector<var_decl*> vars_to_keep;
for (vector<var_decl*>::iterator v = priv_->vars.begin();
v != priv_->vars.end();
++v)
variables vars_to_keep;
for (auto v = priv_->vars.begin(); v != priv_->vars.end(); ++v)
{
if (b->priv_->keep_wrt_id_of_vars_to_keep(*v)
&& b->priv_->keep_wrt_regex_of_vars_to_suppress(*v)
@@ -1658,9 +1829,9 @@ struct corpus_group::priv
std::set<string> corpora_paths;
corpora_type corpora;
istring_function_decl_ptr_map_type fns_map;
vector<function_decl*> fns;
corpus::functions fns;
istring_var_decl_ptr_map_type vars_map;
vector<var_decl*> vars;
corpus::variables vars;
string_elf_symbols_map_type var_symbol_map;
string_elf_symbols_map_type fun_symbol_map;
elf_symbols sorted_var_symbols;
@@ -2096,6 +2267,16 @@ bool
corpus_group::recording_types_reachable_from_public_interface_supported()
{return !get_public_types_pretty_representations()->empty();}
/// Test if a @ref corpus is a @ref corpus_group.
///
/// @param corpus the corpus to consider.
///
/// @return the @ref corpus_group is @p corpus is a corpus group, or
/// nil.
corpus_group_sptr
is_corpus_group(const corpus_sptr& corpus)
{return std::dynamic_pointer_cast<corpus_group>(corpus);}
// </corpus_group stuff>
}// end namespace ir
+196 -118
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2021-2023 Oracle, Inc.
// Copyright (C) 2021-2025 Oracle, Inc.
//
// Author: Jose E. Marchesi
@@ -42,6 +42,10 @@ ABG_END_EXPORT_DECLARATIONS
namespace abigail
{
using std::cerr;
/// Namespace of the reader for the CTF debug information
namespace ctf
{
using std::dynamic_pointer_cast;
@@ -141,6 +145,15 @@ class reader : public elf_based_reader
/// A map associating CTF type ids with libabigail IR types. This
/// is used to reuse already generated types.
string_type_base_sptr_map_type types_map;
vector<type_base_sptr> types_to_canonicalize;
/// Vector of additional types created during the analysis. These
/// types don't have assocaited CTF type IDs.
vector<type_base_sptr> additional_types_to_canonicalize;
/// The vector of types present in types_map. This is used to sort
/// the types before canonicalizing them.
vector<type_base_sptr> types;
/// A set associating unknown CTF type ids
std::set<ctf_id_t> unknown_types_set;
@@ -163,6 +176,10 @@ public:
/// Associate a given CTF type ID with a given libabigail IR type.
///
/// The IR type is a newly created type that needs to be
/// canonicalized at the end of the processing of the current
/// corpus.
///
/// @param dic the dictionnary the type belongs to.
///
/// @param ctf_type the type ID.
@@ -172,9 +189,18 @@ public:
add_type(ctf_dict_t *dic, ctf_id_t ctf_type, type_base_sptr type)
{
string key = dic_type_key(dic, ctf_type);
types_map.insert(std::make_pair(key, type));
if (types_map.insert(std::make_pair(key, type)).second)
types_to_canonicalize.push_back(type);
}
/// Add a type to the vector of types to be (sorted and)
/// canonicalized.
///
/// @param t the type to schedule for canonicalization.
void
add_type(const type_base_sptr& t)
{additional_types_to_canonicalize.push_back(t);}
/// Insert a given CTF unknown type ID.
///
/// @param ctf_type the unknown type ID to be added.
@@ -212,10 +238,14 @@ public:
void
canonicalize_all_types(void)
{
canonicalize_types
(types_map.begin(), types_map.end(),
[](const string_type_base_sptr_map_type::const_iterator& i)
{return i->second;});
for (auto& t: additional_types_to_canonicalize)
types_to_canonicalize.push_back(t);
additional_types_to_canonicalize.clear();
ir::hash_and_canonicalize_types(types_to_canonicalize.begin(),
types_to_canonicalize.end(),
[](vector<type_base_sptr>::iterator& i)
{return *i;});
}
/// Constructor.
@@ -231,11 +261,12 @@ public:
/// that ABI artifacts that are to be compared all need to be
/// created within the same environment.
reader(const string& elf_path,
const vector<char**>& debug_info_root_paths,
const vector<string>& debug_info_root_paths,
environment& env)
: elf_based_reader(elf_path, debug_info_root_paths, env)
: elf_based_reader(elf_path, debug_info_root_paths, env),
ctfa(), ctf_sect(), symtab_sect(), strtab_sect()
{
initialize();
reset();
}
/// Initializer of the reader.
@@ -243,24 +274,32 @@ public:
/// This is useful to clear out the data used by the reader and get
/// it ready to be used again.
///
/// Note that the reader eeps the same environment it has been
/// originally created with.
/// Note that the reader keeps (doesn't clear) the same environment
/// it has been originally created with.
///
/// 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.
/// must be greater than the life time of the resulting @ref reader
/// the context uses resources that are allocated in the
/// environment.
void
initialize()
reset()
{
ctfa = nullptr;
types_map.clear();
types_to_canonicalize.clear();
cur_tu_.reset();
corpus_group().reset();
}
/// Initializer of the reader.
///
/// This first makes sure the data used by the reader is cleared.
/// And then it initlizes it with the information passed in
/// argument.
///
/// This is useful to clear out the data used by the reader and get
/// it ready to be used again.
///
/// Note that the reader keeps the same environment it has been
/// originally created with.
///
/// @param elf_path the new path to the new ELF file to use.
///
/// @param debug_info_root_paths a vector of paths to use to look
@@ -270,22 +309,13 @@ public:
///
/// @param linux_kernel_mode currently not used.
///
/// This is useful to clear out the data used by the reader and get
/// it ready to be used again.
///
/// Note that the reader eeps the same environment it has been
/// originally created with.
///
/// 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.
void
initialize(const string& elf_path,
const vector<char**>& debug_info_root_paths,
bool load_all_types = false,
bool linux_kernel_mode = false)
initialize(const string& elf_path,
const vector<string>& debug_info_root_paths,
bool load_all_types = false,
bool linux_kernel_mode = false)
{
reset();
load_all_types = load_all_types;
linux_kernel_mode = linux_kernel_mode;
elf_based_reader::initialize(elf_path, debug_info_root_paths);
@@ -322,6 +352,16 @@ public:
env()
{return options().env;}
/// Getter of the "do_log" flag.
///
/// This flag tells if we should log about various internal
/// details.
///
/// return the "do_log" flag.
bool
do_log() const
{return options().do_log;}
/// Look for vmlinux.ctfa file in default directory or in
/// directories provided by debug-info-dir command line option,
/// it stores location path in @ref ctfa_file.
@@ -345,7 +385,7 @@ public:
// for vmlinux.ctfa should be provided with --debug-info-dir
// option.
for (const auto& path : debug_info_root_paths())
if (tools_utils::find_file_under_dir(*path, "vmlinux.ctfa", ctfa_file))
if (tools_utils::find_file_under_dir(path, "vmlinux.ctfa", ctfa_file))
return true;
return false;
@@ -363,15 +403,6 @@ public:
elf::reader::read_corpus(status);
corpus_sptr corp = corpus();
if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
&& corpus_group())
{
// Not finding any debug info so far is expected if we are
// building a kABI.
status &= static_cast<abigail::fe_iface::status>
(~STATUS_DEBUG_INFO_NOT_FOUND);
return;
}
if ((status & STATUS_NO_SYMBOLS_FOUND)
|| !(status & STATUS_OK))
@@ -395,17 +426,29 @@ public:
}
const Elf_Scn* ctf_scn = find_ctf_section();
fill_ctf_section(ctf_scn, &ctf_sect);
if (ctf_scn)
fill_ctf_section(ctf_scn, &ctf_sect);
const Elf_Scn* symtab_scn =
elf_helpers::find_section_by_name(elf_handle(), symtab_name);
fill_ctf_section(symtab_scn, &symtab_sect);
if (symtab_scn)
fill_ctf_section(symtab_scn, &symtab_sect);
const Elf_Scn* strtab_scn =
elf_helpers::find_section_by_name(elf_handle(), strtab_name);
fill_ctf_section(strtab_scn, &strtab_sect);
if (strtab_scn)
fill_ctf_section(strtab_scn, &strtab_sect);
status |= fe_iface::STATUS_OK;
if (ctf_scn && symtab_scn && strtab_scn)
status |= fe_iface::STATUS_OK;
else if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
{
// Not finding any debug info so far is expected if we are
// building a kABI.
status &= static_cast<abigail::fe_iface::status>
(~STATUS_DEBUG_INFO_NOT_FOUND);
return;
}
}
/// Process a CTF archive and create libabigail IR for the types,
@@ -422,35 +465,26 @@ public:
corp->add(ir_translation_unit);
cur_transl_unit(ir_translation_unit);
int ctf_err;
ctf_dict_t *ctf_dict, *dict_tmp;
ctf_dict_t *ctf_dict = nullptr, *initial_ctf_dict = nullptr;
const auto symt = symtab();
symtab_reader::symtab_filter filter = symt->make_filter();
filter.set_public_symbols();
std::string dict_name;
if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
&& corpus_group())
ctf_next_t *it = nullptr;
// Iterate through the dictionnaries of the archive and get the
// first one, which should be the parent dictionnary.
initial_ctf_dict = ctf_archive_next(ctfa, /*iterator=*/&it,
/*dict_name=*/nullptr,
/*skip_parent=*/false,
/*ctf_error=*/nullptr);
if (!initial_ctf_dict)
{
tools_utils::base_name(corpus_path(), dict_name);
// remove .* suffix
std::size_t pos = dict_name.find(".");
if (pos != string::npos)
dict_name.erase(pos);
std::replace(dict_name.begin(), dict_name.end(), '-', '_');
std::cerr << "Could not find any dictionnary in the CTF archive\n";
ctf_next_destroy(it);
return;
}
if ((ctf_dict = ctf_dict_open(ctfa,
dict_name.empty() ? NULL : dict_name.c_str(),
&ctf_err)) == NULL)
{
fprintf(stderr, "ERROR dictionary not found\n");
abort();
}
dict_tmp = ctf_dict;
ctf_dict = initial_ctf_dict;
for (const auto& symbol : symtab_reader::filtered_symtab(*symt, filter))
{
std::string sym_name = symbol->get_name();
@@ -479,7 +513,7 @@ public:
add_decl_to_scope(var_declaration,
ir_translation_unit->get_global_scope());
var_declaration->set_is_in_public_symbol_table(true);
maybe_add_var_to_exported_decls(var_declaration.get());
add_var_to_exported_or_undefined_decls(var_declaration);
}
else
{
@@ -499,18 +533,16 @@ public:
add_decl_to_scope(func_declaration,
ir_translation_unit->get_global_scope());
func_declaration->set_is_in_public_symbol_table(true);
maybe_add_fn_to_exported_decls(func_declaration.get());
add_fn_to_exported_or_undefined_decls(func_declaration.get());
}
if (ctf_dict != initial_ctf_dict)
{
ctf_dict_close(initial_ctf_dict);
initial_ctf_dict = ctf_dict;
}
ctf_dict = dict_tmp;
}
ctf_dict_close(ctf_dict);
/* Canonicalize all the types generated above. This must be
done "a posteriori" because the processing of types may
require other related types to not be already
canonicalized. */
canonicalize_all_types();
ctf_next_destroy(it);
}
/// Add a new type declaration to the given libabigail IR corpus CORP.
@@ -661,46 +693,87 @@ public:
corpus::origin origin = corpus()->get_origin();
origin |= corpus::CTF_ORIGIN;
corp->set_origin(origin);
if (corpus_group())
{
origin |= corpus_group()->get_origin();
corpus_group()->set_origin(origin);
}
slurp_elf_info(status);
if (status & fe_iface::STATUS_NO_SYMBOLS_FOUND)
return corpus_sptr();
if (!(origin & corpus::LINUX_KERNEL_BINARY_ORIGIN)
&& (status & fe_iface::STATUS_DEBUG_INFO_NOT_FOUND))
&& (status & fe_iface::STATUS_DEBUG_INFO_NOT_FOUND))
return corp;
int errp;
if ((corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
&& corpus_group())
#ifdef WITH_DEBUG_SELF_COMPARISON
if (env().self_comparison_debug_is_on())
{
if (ctfa == NULL)
corpus_group_sptr g = corpus_group();
if (g)
env().set_self_comparison_debug_input(g);
else
env().set_self_comparison_debug_input(corpus());
}
#endif
tools_utils::timer t;
if (do_log())
t.start();
int errp;
if (corp->get_origin() & corpus::LINUX_KERNEL_BINARY_ORIGIN)
{
if (ctfa == nullptr)
{
std::string ctfa_filename;
if (find_ctfa_file(ctfa_filename))
ctfa = ctf_arc_open(ctfa_filename.c_str(), &errp);
}
}
else
/* Build the ctfa from the contents of the relevant ELF sections,
and process the CTF archive in the read context, if any.
Information about the types, variables, functions, etc contained
in the archive are added to the given corpus. */
/* Build the ctfa from the contents of the relevant ELF sections,
and process the CTF archive in the read context, if any.
Information about the types, variables, functions, etc contained
in the archive are added to the given corpus. */
if (ctfa == nullptr
&& ctf_sect.cts_data
&& symtab_sect.cts_data
&& strtab_sect.cts_data)
ctfa = ctf_arc_bufopen(&ctf_sect, &symtab_sect,
&strtab_sect, &errp);
if (do_log())
{
t.stop();
cerr << "CTF Reader: Reading CTF info in:" << t << "\n";
t.start();
}
env().canonicalization_is_done(false);
if (ctfa == NULL)
status |= fe_iface::STATUS_DEBUG_INFO_NOT_FOUND;
else
{
process_ctf_archive();
/* Canonicalize all the types generated above. This must be
done "a posteriori" because the processing of types may
require other related types to not be already
canonicalized. */
canonicalize_all_types();
corpus()->sort_functions();
corpus()->sort_variables();
}
env().canonicalization_is_done(true);
if (do_log())
{
t.stop();
cerr << "CTF Reader: Building ABG-IR in:" << t << "\n";
}
return corp;
}
@@ -708,6 +781,7 @@ public:
~reader()
{
ctf_close(ctfa);
ctfa = nullptr;
}
}; // end class reader.
@@ -812,16 +886,15 @@ process_ctf_base_type(reader *rdr,
tunit);
type_base_sptr void_type = is_type(type_declaration);
result = is_type_decl(type_declaration);
canonicalize(result);
}
else
{
if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
{
string normalized_type_name = type_name;
integral_type int_type;
if (parse_integral_type(type_name, int_type))
normalized_type_name = int_type.to_string();
real_type real_type;
if (parse_real_type(type_name, real_type))
normalized_type_name = real_type.to_string();
if ((result = lookup_basic_type(normalized_type_name, *corp)))
return result;
}
@@ -862,7 +935,7 @@ build_ir_node_for_variadic_parameter_type(reader &rdr,
type_base_sptr t = env.get_variadic_parameter_type();
decl_base_sptr type_declaration = get_type_declaration(t);
add_decl_to_scope(type_declaration, tunit->get_global_scope());
canonicalize(t);
rdr.add_type(t);
return type_declaration;
}
@@ -883,7 +956,7 @@ build_ir_node_for_void_type(reader& rdr, const translation_unit_sptr& tunit)
const environment& env = rdr.env();
type_base_sptr t = env.get_void_type();
add_decl_to_scope(is_decl(t), tunit->get_global_scope());
canonicalize(t);
rdr.add_type(t);
return is_decl(t);
}
@@ -905,7 +978,7 @@ build_ir_node_for_void_pointer_type(reader& rdr,
const environment& env = rdr.env();
type_base_sptr t = env.get_void_pointer_type();
add_decl_to_scope(is_decl(t), tunit->get_global_scope());
canonicalize(t);
rdr.add_type(t);
return is_decl(t);
}
@@ -1046,7 +1119,7 @@ process_ctf_sou_members(reader *rdr,
public_access,
true /* is_laid_out */,
false /* is_static */,
membinfo.ctm_offset);
is_union_type(sou) ? 0 : membinfo.ctm_offset);
}
if (ctf_errno(ctf_dictionary) != ECTF_NEXT_END)
fprintf(stderr, "ERROR from ctf_member_next\n");
@@ -1231,7 +1304,7 @@ static array_type_def::subrange_sptr
build_array_ctf_range(reader *rdr, ctf_dict_t *dic,
ctf_id_t index, uint64_t nelems)
{
bool is_infinite = false;
bool is_non_finite = false;
corpus_sptr corp = rdr->corpus();
translation_unit_sptr tunit = rdr->cur_transl_unit();
array_type_def::subrange_sptr subrange;
@@ -1247,7 +1320,7 @@ build_array_ctf_range(reader *rdr, ctf_dict_t *dic,
/* for VLAs number of array elements is 0 */
if (upper_bound.get_unsigned_value() == 0 && nelems == 0)
is_infinite = true;
is_non_finite = true;
subrange.reset(new array_type_def::subrange_type(rdr->env(),
"",
@@ -1256,13 +1329,15 @@ build_array_ctf_range(reader *rdr, ctf_dict_t *dic,
index_type,
location(),
translation_unit::LANG_C));
if (!index_type)
subrange->set_size_in_bits(rdr->cur_transl_unit()->get_address_size());
if (!subrange)
return nullptr;
subrange->is_infinite(is_infinite);
subrange->is_non_finite(is_non_finite);
add_decl_to_scope(subrange, tunit->get_global_scope());
canonicalize(subrange);
rdr->add_type(subrange);
return subrange;
}
@@ -1557,7 +1632,7 @@ process_ctf_enum_type(reader *rdr,
return result;
add_decl_to_scope(utype, tunit->get_global_scope());
canonicalize(utype);
rdr->add_type(utype);
/* Iterate over the enum entries. */
enum_type_decl::enumerators enms;
@@ -1620,10 +1695,12 @@ lookup_symbol_in_ctf_archive(ctf_archive_t *ctfa, ctf_dict_t **ctf_dict,
if (ctf_type == CTF_ERR)
{
ctf_dict_t *fp;
ctf_next_t *i = NULL;
const char *arcname;
ctf_next_t *i = nullptr;
const char *arcname = nullptr;
while ((fp = ctf_archive_next(ctfa, &i, &arcname, 1, &ctf_err)) != NULL)
while ((fp = ctf_archive_next(ctfa, &i, &arcname,
/*skip_parent=*/true,
&ctf_err)) != nullptr)
{
if ((ctf_type = ctf_lookup_by_symbol_name (fp, sym_name)) == CTF_ERR)
ctf_type = ctf_lookup_variable(fp, sym_name);
@@ -1669,16 +1746,25 @@ fill_ctf_section(const Elf_Scn *elf_section, ctf_sect_t *ctf_section)
/// from a given ELF file.
///
/// @param elf_path the patch of some ELF file.
///
/// @param debug_info_root_paths the paths to where to find the debug
/// info.
///
/// @param env a libabigail IR environment.
elf_based_reader_sptr
create_reader(const std::string& elf_path,
const vector<char**>& debug_info_root_paths,
const vector<string>& debug_info_root_paths,
environment& env)
{
reader_sptr result(new reader(elf_path,
debug_info_root_paths,
env));
#ifdef WITH_DEBUG_SELF_COMPARISON
if (env.self_comparison_debug_is_on())
env.set_self_comparison_debug_input(result->corpus());
#endif
return result;
}
@@ -1690,20 +1776,12 @@ create_reader(const std::string& elf_path,
/// @param elf_path the path to the elf file the context is to be used
/// for.
///
/// @param environment the environment used by the current context.
/// This environment contains resources needed by the 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 debug_info_root_paths the paths pointing to where to find
/// the debug info.
void
reset_reader(elf_based_reader& rdr,
const std::string& elf_path,
const vector<char**>& debug_info_root_path)
const vector<string>& debug_info_root_path)
{
ctf::reader& r = dynamic_cast<reader&>(rdr);
r.initialize(elf_path, debug_info_root_path);
+218 -143
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2017-2023 Red Hat, Inc.
// Copyright (C) 2017-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -203,14 +203,43 @@ default_reporter::report(const enum_diff& d, ostream& out,
i != sorted_changed_enumerators.end();
++i)
{
out << indent
<< " '"
<< (first->get_is_anonymous()
? i->first.get_name()
: i->first.get_qualified_name())
<< "' from value '"
<< i->first.get_value() << "' to '"
<< i->second.get_value() << "'";
out << indent;
if (i->first.get_value() != i->second.get_value())
{
out << " '"
<< (first->get_is_anonymous()
? i->first.get_name()
: i->first.get_qualified_name())
<< "' from value '"
<< i->first.get_value() << "' to '"
<< i->second.get_value() << "'";
}
else if (i->first.get_name() != i->second.get_name())
{
out << "from '"
<< (first->get_is_anonymous()
? i->first.get_name()
: i->first.get_qualified_name())
<< " = " << i->first.get_value()
<< "' to '"
<< (second->get_is_anonymous()
? i->second.get_name()
: i->second.get_qualified_name())
<< " = " << i->second.get_value()
<< "'";
}
else
{
out << "enumerator change from '"
<< i->first.get_name()
<< " = "
<< i->first.get_value()
<< "' to '"
<< i->second.get_name()
<< " = "
<< i->second.get_value()
<< "' could not be determined - please report as a bug";
}
report_loc_info(second, *ctxt, out);
out << "\n";
}
@@ -245,7 +274,7 @@ default_reporter::report_non_type_typedef_changes(const typedef_diff &d,
maybe_report_diff_for_member(f, s, d.context(), out, indent);
if ((filtering::has_harmless_name_change(f, s)
if ((filtering::has_harmless_name_change(f, s, d.context())
&& ((d.context()->get_allowed_category()
& HARMLESS_DECL_NAME_CHANGE_CATEGORY)
|| d.context()->show_leaf_changes_only()))
@@ -522,6 +551,100 @@ default_reporter::report(const reference_diff& d, ostream& out,
}
}
/// Report the local changes carried by a @ref ptr_to_mbr_diff diff
/// node.
///
/// This is a subroutine of the method default_reporter::report() that
/// emits change report for @ref ptr_to_mbr_diff node.
///
/// @param d the diff node to consider
///
/// @param out the output stream to emit the report to.
///
/// @param indent the indentation string (spaces) to use in the
/// report.
///
/// @return truf iff a report was emitted to the output stream.
bool
default_reporter::report_local_ptr_to_mbr_type_changes(const ptr_to_mbr_diff& d,
std::ostream& out,
const std::string& indent) const
{
if (!d.to_be_reported())
return false;
ptr_to_mbr_type_sptr f = d.first_ptr_to_mbr_type(),
s = d.second_ptr_to_mbr_type();
enum change_kind k = ir::NO_CHANGE_KIND;
equals(*d.first_ptr_to_mbr_type(), *d.second_ptr_to_mbr_type(), &k);
if (k & ALL_LOCAL_CHANGES_MASK)
{
string f_repr = f->get_pretty_representation(),
s_repr = s->get_pretty_representation();
out << indent;
out << "pointer-to-member type changed from: '"
<< f_repr << " to: '"<< s_repr << "'\n";
return true;
}
return false;
}
/// Emit a textual report about the changes carried by a @ref
/// ptr_to_mbr_diff diff node.
///
/// @param out the output stream to emit the report to.
///
/// @param indent the indentation string to use for the report.
void
default_reporter::report(const ptr_to_mbr_diff& d,
std::ostream& out,
const std::string& indent) const
{
if (!d.to_be_reported())
return;
report_local_ptr_to_mbr_type_changes(d, out, indent);
if (diff_sptr dif = d.member_type_diff())
{
RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2
(dif,"data member type of pointer-to-member");
if (dif->to_be_reported())
{
out << indent
<< "in data member type '"
<< dif->first_subject()->get_pretty_representation()
<< "' of pointed-to-member type '"
<< d.first_ptr_to_mbr_type()->get_pretty_representation()
<< "'";
report_loc_info(dif->second_subject(), *d.context(), out);
out << ":\n";
dif->report(out, indent + " ");
}
}
if (diff_sptr dif = d.containing_type_diff())
{
RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2
(dif,"containing type of pointer-to-member");
if (dif->to_be_reported())
{
out << indent
<< "in containing type '"
<< dif->first_subject()->get_pretty_representation()
<< "' of pointed-to-member type '"
<< d.first_ptr_to_mbr_type()->get_pretty_representation()
<< "'";
report_loc_info(dif->second_subject(), *d.context(), out);
out << ":\n";
dif->report(out, indent + " ");
}
}
}
/// Emit a textual report about the a @ref fn_parm_diff instance.
///
/// @param d the @ref fn_parm_diff to consider.
@@ -735,6 +858,24 @@ default_reporter::report(const array_diff& d, ostream& out,
d.second_array(),
d.context(),
out, indent);
if (d.any_subrange_diff_to_be_reported())
{
int subrange_index = 0;
for (const auto& subrange_diff : d.subrange_diffs())
{
++subrange_index;
if (subrange_diff->to_be_reported())
{
out << indent << "array subrange ";
if (d.subrange_diffs().size() > 1)
out << subrange_index << " ";
out << "changed: \n";
subrange_diff->report(out, indent + " ");
}
}
}
}
/// Generates a report for an intance of @ref base_diff.
@@ -1440,7 +1581,7 @@ default_reporter::report(const union_diff& d, ostream& out,
d.class_or_union_diff::report(out, indent);
if (d.context()->get_allowed_category() & HARMLESS_UNION_CHANGE_CATEGORY
if (d.context()->get_allowed_category() & HARMLESS_UNION_OR_CLASS_CHANGE_CATEGORY
&& filtering::union_diff_has_harmless_changes(&d))
{
// The user wants to see harmless changes and the union diff we
@@ -1497,10 +1638,7 @@ default_reporter::report(const distinct_diff& d, ostream& out,
type_base_sptr fs = strip_typedef(is_type(f)),
ss = strip_typedef(is_type(s));
if (diff)
diff->report(out, indent + " ");
else
report_size_and_alignment_changes(f, s, d.context(), out, indent);
report_size_and_alignment_changes(f, s, d.context(), out, indent);
}
/// Serialize a report of the changes encapsulated in the current
@@ -1792,32 +1930,29 @@ default_reporter::report(const corpus_diff& d, ostream& out,
out << indent << s.net_num_func_removed() << " Removed functions:\n\n";
bool emitted = false;
vector<function_decl*>sorted_deleted_fns;
corpus::functions sorted_deleted_fns;
sort_string_function_ptr_map(d.priv_->deleted_fns_, sorted_deleted_fns);
for (vector<function_decl*>::const_iterator i =
sorted_deleted_fns.begin();
i != sorted_deleted_fns.end();
++i)
for (auto f : sorted_deleted_fns)
{
if (d.priv_->deleted_function_is_suppressed(*i))
if (d.priv_->deleted_function_is_suppressed(f))
continue;
out << indent
<< " ";
out << "[D] ";
out << "'" << (*i)->get_pretty_representation() << "'";
out << "'" << (f)->get_pretty_representation() << "'";
if (ctxt->show_linkage_names())
{
out << " {";
show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
show_linkage_name_and_aliases(out, "", *(f)->get_symbol(),
d.first_corpus()->get_fun_symbol_map());
out << "}";
}
out << "\n";
if (is_member_function(*i) && get_member_function_is_virtual(*i))
if (is_member_function(f) && get_member_function_is_virtual(f))
{
class_decl_sptr c =
is_class_type(is_method_type((*i)->get_type())->get_class_type());
is_class_type(is_method_type(f->get_type())->get_class_type());
out << indent
<< " "
<< "note that this removes an entry from the vtable of "
@@ -1830,6 +1965,21 @@ default_reporter::report(const corpus_diff& d, ostream& out,
out << "\n";
}
if (size_t num_changed = s.num_func_with_incompatible_changes())
{
if (num_changed == 1)
out << indent << "1 function with incompatible sub-type changes:\n\n";
else if (num_changed > 1)
out << indent << num_changed
<< " functions with incompatible sub-type changes:\n\n";
sort_function_decl_diffs(const_cast<corpus_diff&>(d).
incompatible_changed_functions());
for (auto& fn_diff : d.incompatible_changed_functions())
if (fn_diff)
emit_changed_fn_report(ctxt, fn_diff, out, indent);
}
if (ctxt->show_added_fns())
{
if (s.net_num_func_added() == 1)
@@ -1838,13 +1988,11 @@ default_reporter::report(const corpus_diff& d, ostream& out,
out << indent << s.net_num_func_added()
<< " Added functions:\n\n";
bool emitted = false;
vector<function_decl*> sorted_added_fns;
corpus::functions sorted_added_fns;
sort_string_function_ptr_map(d.priv_->added_fns_, sorted_added_fns);
for (vector<function_decl*>::const_iterator i = sorted_added_fns.begin();
i != sorted_added_fns.end();
++i)
for (auto f : sorted_added_fns)
{
if (d.priv_->added_function_is_suppressed(*i))
if (d.priv_->added_function_is_suppressed(f))
continue;
out
@@ -1852,21 +2000,21 @@ default_reporter::report(const corpus_diff& d, ostream& out,
<< " ";
out << "[A] ";
out << "'"
<< (*i)->get_pretty_representation()
<< f->get_pretty_representation()
<< "'";
if (ctxt->show_linkage_names())
{
out << " {";
show_linkage_name_and_aliases
(out, "", *(*i)->get_symbol(),
(out, "", *f->get_symbol(),
d.second_corpus()->get_fun_symbol_map());
out << "}";
}
out << "\n";
if (is_member_function(*i) && get_member_function_is_virtual(*i))
if (is_member_function(f) && get_member_function_is_virtual(f))
{
class_decl_sptr c =
is_class_type(is_method_type((*i)->get_type())->get_class_type());
is_class_type(is_method_type(f->get_type())->get_class_type());
out << indent
<< " "
<< "note that this adds a new entry to the vtable of "
@@ -1880,8 +2028,8 @@ default_reporter::report(const corpus_diff& d, ostream& out,
}
if (ctxt->show_changed_fns())
if (size_t num_changed = s.net_num_non_incompatible_func_changed())
{
size_t num_changed = s.num_func_changed() - s.num_changed_func_filtered_out();
if (num_changed == 1)
out << indent << "1 function with some indirect sub-type change:\n\n";
else if (num_changed > 1)
@@ -1891,71 +2039,11 @@ default_reporter::report(const corpus_diff& d, ostream& out,
vector<function_decl_diff_sptr> sorted_changed_fns;
sort_string_function_decl_diff_sptr_map(d.priv_->changed_fns_map_,
sorted_changed_fns);
for (vector<function_decl_diff_sptr>::const_iterator i =
sorted_changed_fns.begin();
i != sorted_changed_fns.end();
++i)
{
diff_sptr diff = *i;
if (!diff)
continue;
if (diff->to_be_reported())
{
function_decl_sptr fn = (*i)->first_function_decl();
out << indent << " [C] '"
<< fn->get_pretty_representation() << "'";
report_loc_info((*i)->first_function_decl(), *ctxt, out);
out << " has some indirect sub-type changes:\n";
if (// The symbol of the function has aliases and the
// function is not a cdtor (yeah because c++ cdtors
// usually have several aliases).
(fn->get_symbol()->has_aliases()
&& !(is_member_function(fn)
&& get_member_function_is_ctor(fn))
&& !(is_member_function(fn)
&& get_member_function_is_dtor(fn)))
|| // We are in C and the name of the function is
// different from the symbol name -- without
// taking the possible symbol version into
// account (this usually means the programmers
// was playing tricks with symbol names and
// versions).
(is_c_language(get_translation_unit(fn)->get_language())
&& fn->get_name() != fn->get_symbol()->get_name()))
{
// As the name of the symbol of the function doesn't
// seem to be obvious here, make sure to tell the
// user about the name of the (function) symbol she
// is looking at here.
int number_of_aliases =
fn->get_symbol()->get_number_of_aliases();
if (number_of_aliases == 0)
{
out << indent << " "
<< "Please note that the exported symbol of "
"this function is "
<< fn->get_symbol()->get_id_string()
<< "\n";
}
else
{
out << indent << " "
<< "Please note that the symbol of this function is "
<< fn->get_symbol()->get_id_string()
<< "\n and it aliases symbol";
if (number_of_aliases > 1)
out << "s";
out << ": "
<< fn->get_symbol()->get_aliases_id_string(false)
<< "\n";
}
}
diff->report(out, indent + " ");
// Extra spacing.
out << "\n";
}
}
for (auto& fn_diff : sorted_changed_fns)
if (fn_diff && !filtering::has_incompatible_fn_or_var_change(fn_diff))
emit_changed_fn_report(ctxt, fn_diff, out, indent,
/*indirect_changed_subtypes=*/true,
/*emit_redundant_fns=*/false);
// Changed functions have extra spacing already. No new line here.
}
@@ -1969,17 +2057,14 @@ default_reporter::report(const corpus_diff& d, ostream& out,
<< " Removed variables:\n\n";
string n;
bool emitted = false;
vector<var_decl*> sorted_deleted_vars;
corpus::variables sorted_deleted_vars;
sort_string_var_ptr_map(d.priv_->deleted_vars_, sorted_deleted_vars);
for (vector<var_decl*>::const_iterator i =
sorted_deleted_vars.begin();
i != sorted_deleted_vars.end();
++i)
for (auto v : sorted_deleted_vars)
{
if (d.priv_->deleted_variable_is_suppressed(*i))
if (d.priv_->deleted_variable_is_suppressed(v))
continue;
n = (*i)->get_pretty_representation();
n = v->get_pretty_representation();
out << indent
<< " ";
@@ -1990,7 +2075,7 @@ default_reporter::report(const corpus_diff& d, ostream& out,
if (ctxt->show_linkage_names())
{
out << " {";
show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
show_linkage_name_and_aliases(out, "", *v->get_symbol(),
d.first_corpus()->get_var_symbol_map());
out << "}";
}
@@ -2001,6 +2086,21 @@ default_reporter::report(const corpus_diff& d, ostream& out,
out << "\n";
}
if (size_t num_changed = s.num_var_with_incompatible_changes())
{
if (num_changed == 1)
out << indent << "1 variable with incompatible sub-type changes:\n\n";
else if (num_changed > 1)
out << indent << num_changed
<< " variables with incompatible sub-type changes:\n\n";
sort_var_diffs(const_cast<corpus_diff&>(d).
incompatible_changed_variables());
for (auto& var_diff : d.incompatible_changed_variables())
if (var_diff)
emit_changed_var_report(ctxt, var_diff, out, indent);
}
if (ctxt->show_added_vars())
{
if (s.net_num_vars_added() == 1)
@@ -2010,17 +2110,14 @@ default_reporter::report(const corpus_diff& d, ostream& out,
<< " Added variables:\n\n";
string n;
bool emitted = false;
vector<var_decl*> sorted_added_vars;
corpus::variables sorted_added_vars;
sort_string_var_ptr_map(d.priv_->added_vars_, sorted_added_vars);
for (vector<var_decl*>::const_iterator i =
sorted_added_vars.begin();
i != sorted_added_vars.end();
++i)
for (auto v : sorted_added_vars)
{
if (d.priv_->added_variable_is_suppressed(*i))
if (d.priv_->added_variable_is_suppressed(v))
continue;
n = (*i)->get_pretty_representation();
n = v->get_pretty_representation();
out << indent
<< " ";
@@ -2029,7 +2126,7 @@ default_reporter::report(const corpus_diff& d, ostream& out,
if (ctxt->show_linkage_names())
{
out << " {";
show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
show_linkage_name_and_aliases(out, "", *v->get_symbol(),
d.second_corpus()->get_var_symbol_map());
out << "}";
}
@@ -2041,9 +2138,8 @@ default_reporter::report(const corpus_diff& d, ostream& out,
}
if (ctxt->show_changed_vars())
if (size_t num_changed = s.net_num_non_incompatible_var_changed())
{
size_t num_changed =
s.num_vars_changed() - s.num_changed_vars_filtered_out();
if (num_changed == 1)
out << indent << "1 Changed variable:\n\n";
else if (num_changed > 1)
@@ -2051,31 +2147,10 @@ default_reporter::report(const corpus_diff& d, ostream& out,
<< " Changed variables:\n\n";
string n1, n2;
for (var_diff_sptrs_type::const_iterator i =
d.priv_->sorted_changed_vars_.begin();
i != d.priv_->sorted_changed_vars_.end();
++i)
{
diff_sptr diff = *i;
if (!diff)
continue;
if (!diff->to_be_reported())
continue;
n1 = diff->first_subject()->get_pretty_representation();
n2 = diff->second_subject()->get_pretty_representation();
out << indent << " [C] '" << n1 << "' was changed";
if (n1 != n2)
out << " to '" << n2 << "'";
report_loc_info(diff->second_subject(), *ctxt, out);
out << ":\n";
diff->report(out, indent + " ");
// Extra spacing.
out << "\n";
}
for (auto& var_diff : d.priv_->sorted_changed_vars_)
if (var_diff
&& !filtering::has_incompatible_fn_or_var_change(var_diff))
emit_changed_var_report(ctxt, var_diff, out, indent);
// Changed variables have extra spacing already. No new line here.
}
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
#include <cstring>
+2604 -930
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2022-2023 Red Hat, Inc.
// Copyright (C) 2022-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -49,7 +49,7 @@ struct elf_based_reader::priv
///
/// @param env the environment used by the reader.
elf_based_reader::elf_based_reader(const std::string& elf_path,
const vector<char**>& debug_info_root_paths,
const vector<string>& debug_info_root_paths,
environment& env)
: elf::reader(elf_path, debug_info_root_paths, env),
priv_(new priv)
@@ -72,7 +72,7 @@ elf_based_reader::~elf_based_reader()
/// split debug info files.
void
elf_based_reader::initialize(const std::string& elf_path,
const vector<char**>& debug_info_root_paths)
const vector<string>& debug_info_root_paths)
{
elf::reader::initialize(elf_path, debug_info_root_paths);
priv_->initialize();
@@ -88,7 +88,7 @@ void
elf_based_reader::initialize(const std::string& corpus_path)
{
fe_iface::initialize(corpus_path);
vector<char**> v;
vector<string> v;
initialize(corpus_path, v, /*load_all_type=*/false,
/*linux_kernel_mode=*/false);
}
@@ -107,8 +107,8 @@ ir::corpus_sptr
elf_based_reader::read_and_add_corpus_to_group(ir::corpus_group& group,
fe_iface::status& status)
{
group.add_corpus(corpus());
ir::corpus_sptr corp = read_corpus(status);
group.add_corpus(corp);
return corp;
}
+6 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2020-2023 Google, Inc.
// Copyright (C) 2020-2025 Google, Inc.
/// @file
///
@@ -287,6 +287,11 @@ e_machine_to_string(GElf_Half e_machine)
return "elf-tilera-tilegx";
#endif
#ifdef HAVE_EM_RISCV_MACRO
case EM_RISCV:
return "elf-riscv";
#endif
case EM_NUM:
return "elf-last-arch-number";
case EM_ALPHA:
+2 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2020-2023 Google, Inc.
// Copyright (C) 2020-2025 Google, Inc.
/// @file
///
@@ -13,6 +13,7 @@
#include "config.h"
#include <elfutils/libdwfl.h>
#include <elfutils/libdwelf.h>
#include <gelf.h>
#include <string>
+132 -227
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2022-2023 Red Hat, Inc.
// Copyright (C) 2022-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -100,151 +100,6 @@ find_alt_dwarf_debug_info_link(Dwfl_Module *elf_module,
return false;
}
/// Find alternate debuginfo file of a given "link" under a set of
/// root directories.
///
/// The link is a string that is read by the function
/// find_alt_dwarf_debug_info_link(). That link is a path that is relative
/// to a given debug info file, e.g, "../../../.dwz/something.debug".
/// It designates the alternate debug info file associated to a given
/// debug info file.
///
/// This function will thus try to find the .dwz/something.debug file
/// under some given root directories.
///
/// @param root_dirs the set of root directories to look from.
///
/// @param alt_file_name a relative path to the alternate debug info
/// file to look for.
///
/// @param alt_file_path the resulting absolute path to the alternate
/// debuginfo path denoted by @p alt_file_name and found under one of
/// the directories in @p root_dirs. This is set iff the function
/// returns true.
///
/// @return true iff the function found the alternate debuginfo file.
static bool
find_alt_dwarf_debug_info_path(const vector<char**> root_dirs,
const string &alt_file_name,
string &alt_file_path)
{
if (alt_file_name.empty())
return false;
string altfile_name = tools_utils::trim_leading_string(alt_file_name, "../");
// In case the alt dwarf debug info file is to be found under
// "/usr/lib/debug", look for it under the provided root directories
// instead.
altfile_name = tools_utils::trim_leading_string(altfile_name,
"/usr/lib/debug/");
for (vector<char**>::const_iterator i = root_dirs.begin();
i != root_dirs.end();
++i)
if (tools_utils::find_file_under_dir(**i, altfile_name, alt_file_path))
return true;
return false;
}
/// Return the alternate debug info associated to a given main debug
/// info file.
///
/// @param elf_module the elf module to consider.
///
/// @param debug_root_dirs a set of root debuginfo directories under
/// which too look for the alternate debuginfo file.
///
/// @param alt_file_name output parameter. This is set to the file
/// path of the alternate debug info file associated to @p elf_module.
/// This is set iff the function returns a non-null result.
///
/// @param alt_fd the file descriptor used to access the alternate
/// debug info. If this parameter is set by the function, then the
/// caller needs to fclose it, otherwise the file descriptor is going
/// to be leaked. Note however that on recent versions of elfutils
/// where libdw.h contains the function dwarf_getalt(), this parameter
/// is set to 0, so it doesn't need to be fclosed.
///
/// Note that the alternate debug info file is a DWARF extension as of
/// DWARF 4 ans is decribed at
/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
///
/// @return the alternate debuginfo, or null. If @p alt_fd is
/// non-zero, then the caller of this function needs to call
/// dwarf_end() on the returned alternate debuginfo pointer,
/// otherwise, it's going to be leaked.
static Dwarf*
find_alt_dwarf_debug_info(Dwfl_Module *elf_module,
const vector<char**> debug_root_dirs,
string& alt_file_name,
int& alt_fd)
{
if (elf_module == 0)
return 0;
Dwarf* result = 0;
find_alt_dwarf_debug_info_link(elf_module, alt_file_name);
#ifdef LIBDW_HAS_DWARF_GETALT
// We are on recent versions of elfutils where the function
// dwarf_getalt exists, so let's use it.
Dwarf_Addr bias = 0;
Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
result = dwarf_getalt(dwarf);
alt_fd = 0;
#else
// We are on an old version of elfutils where the function
// dwarf_getalt doesn't exist yet, so let's open code its
// functionality
char *alt_name = 0;
const char *file_name = 0;
void **user_data = 0;
Dwarf_Addr low_addr = 0;
char *alt_file = 0;
file_name = dwfl_module_info(elf_module, &user_data,
&low_addr, 0, 0, 0, 0, 0);
alt_fd = dwfl_standard_find_debuginfo(elf_module, user_data,
file_name, low_addr,
alt_name, file_name,
0, &alt_file);
result = dwarf_begin(alt_fd, DWARF_C_READ);
#endif
if (result == 0)
{
// So we didn't find the alternate debuginfo file from the
// information that is in the debuginfo file associated to
// elf_module. Maybe the alternate debuginfo file is located
// under one of the directories in debug_root_dirs. So let's
// look in there.
string alt_file_path;
if (!find_alt_dwarf_debug_info_path(debug_root_dirs,
alt_file_name,
alt_file_path))
return result;
// If we reach this point it means we have found the path to the
// alternate debuginfo file and it's in alt_file_path. So let's
// open it and read it.
alt_fd = open(alt_file_path.c_str(), O_RDONLY);
if (alt_fd == -1)
return result;
result = dwarf_begin(alt_fd, DWARF_C_READ);
#ifdef LIBDW_HAS_DWARF_GETALT
Dwarf_Addr bias = 0;
Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
dwarf_setalt(dwarf, result);
#endif
}
return result;
}
/// Private data of the @ref elf::reader type.
struct reader::priv
{
@@ -257,7 +112,15 @@ struct reader::priv
// demand.
mutable symtab_reader::symtab_sptr symt;
// Where split debug info is to be searched for on disk.
vector<char**> debug_info_root_paths;
vector<string> debug_info_root_paths;
// The formatted string version of debug_info_root_paths. The
// format is according to what elfutils expects. For the details of
// what elfutils expects, please read the comments of the function
// dwfl_build_id_find_elf in /usr/include/elfutils/libdwfl.h.
string formated_di_root_paths;
// A pointer to where the string held by formated_di_root_paths is.
// This is fed to elfutils.
char* raw_formated_di_root_paths = nullptr;
// Some very useful callback functions that elfutils needs to
// perform various tasks.
Dwfl_Callbacks offline_callbacks;
@@ -282,7 +145,7 @@ struct reader::priv
Elf_Scn* btf_section = nullptr;
priv(reader& reeder, const std::string& elf_path,
const vector<char**>& debug_info_roots)
const vector<string>& debug_info_roots)
: rdr(reeder)
{
rdr.corpus_path(elf_path);
@@ -300,7 +163,7 @@ struct reader::priv
/// @param debug_info_roots the vector of new directories where to
/// look for split debug info file.
void
initialize(const vector<char**>& debug_info_roots)
initialize(const vector<string>& debug_info_roots)
{
clear_alt_dwarf_debug_info_data();
clear_alt_ctf_debug_info_data();
@@ -311,6 +174,8 @@ struct reader::priv
dt_needed.clear();
symt.reset();
debug_info_root_paths = debug_info_roots;
formated_di_root_paths.clear();
raw_formated_di_root_paths = nullptr;
memset(&offline_callbacks, 0, sizeof(offline_callbacks));
dwfl_handle.reset();
elf_module = nullptr;
@@ -324,6 +189,49 @@ struct reader::priv
alt_ctf_fd = 0;
}
/// Initialize the debug info root path. The format of this path is
/// described in /usr/include/elfutils/libdwfl.h in the comment for
/// the function dwfl_build_id_find_elf.
///
/// The string must start with '-' to disable CRC32 checksum
/// validation. Directories must be separated by the ':' character.
/// The search order depends on if each path is absolute or relative
/// as described by that comment.
///
/// In any case, let's format the debuginfo search path here for
/// elfutils consumption.
void
initialize_debug_info_root_paths()
{
vector<string> root_paths = debug_info_root_paths;
for (auto path : debug_info_root_paths)
if (tools_utils::string_begins_with(path, "/"))
{
// For absolute root directories, let's add all the
// sub-directories of these directories that contain a
// (debug info) file. This can be helpful to help elfutils
// find alternate debuginfo files when the altdebuginfolink
// is itself an absolute file path that is contained under
// the root directory. This what we see in PR30329 and its
// associated regression test in test-abidiff-exit.cc
vector<string> additional_subdirs;
tools_utils::get_file_path_dirs_under_dir(path, additional_subdirs);
for (auto& subdir : additional_subdirs)
root_paths.push_back(subdir);
}
for (auto path : root_paths)
{
if (formated_di_root_paths.empty())
formated_di_root_paths = "-";
if (!path.empty())
formated_di_root_paths += path + ":";
}
raw_formated_di_root_paths =
const_cast<char*>(formated_di_root_paths.c_str());
}
/// Setup the necessary plumbing to open the ELF file and find all
/// the associated split debug info files.
///
@@ -333,10 +241,11 @@ struct reader::priv
crack_open_elf_file()
{
// Initialize the callback functions used by elfutils.
initialize_debug_info_root_paths();
elf_helpers::initialize_dwfl_callbacks(offline_callbacks,
debug_info_root_paths.empty()
formated_di_root_paths.empty()
? nullptr
: debug_info_root_paths.front());
: &raw_formated_di_root_paths);
// Create a handle to the DWARF Front End Library that we'll need.
dwfl_handle = elf_helpers::create_new_dwfl_handle(offline_callbacks);
@@ -358,25 +267,6 @@ struct reader::priv
ABG_ASSERT(elf_handle);
}
/// Find the alternate debuginfo file associated to a given elf file.
///
/// @param elf_module represents the elf file to consider.
///
/// @param alt_file_name the resulting path to the alternate
/// debuginfo file found. This is set iff the function returns a
/// non-nil value.
Dwarf*
find_alt_dwarf_debug_info(Dwfl_Module* elf_module,
string& alt_file_name,
int& alt_fd)
{
Dwarf *result = 0;
result = elf::find_alt_dwarf_debug_info(elf_module,
debug_info_root_paths,
alt_file_name, alt_fd);
return result;
}
/// Clear the resources related to the alternate DWARF data.
void
clear_alt_dwarf_debug_info_data()
@@ -405,24 +295,10 @@ struct reader::priv
if (dwarf_handle)
return;
// First let's see if the ELF file that was cracked open does have
// some DWARF debug info embedded.
Dwarf_Addr bias = 0;
dwarf_handle = dwfl_module_getdwarf(elf_module, &bias);
// If no debug info was found in the binary itself, then look for
// split debuginfo files under multiple possible debuginfo roots.
for (vector<char**>::const_iterator i = debug_info_root_paths.begin();
dwarf_handle == 0 && i != debug_info_root_paths.end();
++i)
{
offline_callbacks.debuginfo_path = *i;
dwarf_handle = dwfl_module_getdwarf(elf_module, &bias);
}
alt_dwarf_handle = find_alt_dwarf_debug_info(elf_module,
alt_dwarf_path,
alt_dwarf_fd);
alt_dwarf_handle = dwarf_getalt(dwarf_handle);
find_alt_dwarf_debug_info_link(elf_module, alt_dwarf_path);
}
/// Clear the resources related to the alternate CTF data.
@@ -467,7 +343,7 @@ struct reader::priv
for (const auto& path : rdr.debug_info_root_paths())
{
std::string file_path;
if (!tools_utils::find_file_under_dir(*path, name, file_path))
if (!tools_utils::find_file_under_dir(path, name, file_path))
continue;
if ((alt_ctf_fd = open(file_path.c_str(), O_RDONLY)) == -1)
@@ -513,7 +389,7 @@ struct reader::priv
///
/// @param env the environment which the reader operates in.
reader::reader(const string& elf_path,
const vector<char**>& debug_info_roots,
const vector<string>& debug_info_roots,
ir::environment& env)
: fe_iface(elf_path, env),
priv_(new priv(*this, elf_path, debug_info_roots))
@@ -539,7 +415,7 @@ reader::~reader()
/// for split debug information files.
void
reader::initialize(const std::string& elf_path,
const vector<char**>& debug_info_roots)
const vector<string>& debug_info_roots)
{
fe_iface::initialize(elf_path);
corpus_path(elf_path);
@@ -559,7 +435,7 @@ reader::initialize(const std::string& elf_path,
void
reader::initialize(const std::string& elf_path)
{
vector<char**> v;
vector<string> v;
initialize(elf_path, v);
}
@@ -568,7 +444,7 @@ reader::initialize(const std::string& elf_path)
///
/// @return the vector of directory paths to look into for split
/// debug information files.
const vector<char**>&
const vector<string>&
reader::debug_info_root_paths() const
{return priv_->debug_info_root_paths;}
@@ -769,7 +645,24 @@ reader::symtab() const
priv_->symt = symtab_reader::symtab::load
(elf_handle(), options().env,
[&](const elf_symbol_sptr& symbol)
{return suppr::is_elf_symbol_suppressed(*this, symbol);});
{
// This closure determines if a given symbol is suppressed by
// taking into accont symbol aliases. Basically, a symbol is
// suppressed if all its aliases are suppressed.
if (!symbol)
return false;
if (!suppr::is_elf_symbol_suppressed(*this, symbol))
return false;
for (elf_symbol_sptr a = symbol->get_next_alias();
a && a.get() != symbol->get_main_symbol().get();
a = a->get_next_alias())
{
if (!suppr::is_elf_symbol_suppressed(*this, a))
return false;
}
return true;
}
);
if (!priv_->symt)
std::cerr << "Symbol table of '" << corpus_path()
@@ -788,13 +681,12 @@ reader::symtab() const
elf_symbol_sptr
reader::function_symbol_is_exported(GElf_Addr symbol_address) const
{
elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
elf_symbol_sptr symbol =
symtab()->function_symbol_is_exported(symbol_address);
if (!symbol)
return symbol;
if (!symbol->is_function() || !symbol->is_public())
return elf_symbol_sptr();
address_set_sptr set;
bool looking_at_linux_kernel_binary =
load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
@@ -820,13 +712,11 @@ reader::function_symbol_is_exported(GElf_Addr symbol_address) const
elf_symbol_sptr
reader::variable_symbol_is_exported(GElf_Addr symbol_address) const
{
elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
elf_symbol_sptr symbol =
symtab()->variable_symbol_is_exported(symbol_address);
if (!symbol)
return symbol;
if (!symbol->is_variable() || !symbol->is_public())
return elf_symbol_sptr();
address_set_sptr set;
bool looking_at_linux_kernel_binary =
load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
@@ -849,23 +739,20 @@ reader::variable_symbol_is_exported(GElf_Addr symbol_address) const
elf_symbol_sptr
reader::function_symbol_is_exported(const string& name) const
{
const elf_symbols& syms = symtab()->lookup_symbol(name);
for (auto s : syms)
const elf_symbol_sptr s = symtab()->function_symbol_is_exported(name);
if (s && s->is_function() && s->is_public())
{
if (s->is_function() && s->is_public())
{
bool looking_at_linux_kernel_binary =
(load_in_linux_kernel_mode()
&& elf_helpers::is_linux_kernel(elf_handle()));
bool looking_at_linux_kernel_binary =
(load_in_linux_kernel_mode()
&& elf_helpers::is_linux_kernel(elf_handle()));
if (looking_at_linux_kernel_binary)
{
if (s->is_in_ksymtab())
return s;
}
else
if (looking_at_linux_kernel_binary)
{
if (s->is_in_ksymtab())
return s;
}
else
return s;
}
return elf_symbol_sptr();
}
@@ -879,26 +766,42 @@ reader::function_symbol_is_exported(const string& name) const
elf_symbol_sptr
reader::variable_symbol_is_exported(const string& name) const
{
const elf_symbols& syms = symtab()->lookup_symbol(name);
for (auto s : syms)
const elf_symbol_sptr s = symtab()->variable_symbol_is_exported(name);
if (s && s->is_variable() && s->is_public())
{
if (s->is_variable() && s->is_public())
{
bool looking_at_linux_kernel_binary =
(load_in_linux_kernel_mode()
&& elf_helpers::is_linux_kernel(elf_handle()));
bool looking_at_linux_kernel_binary =
(load_in_linux_kernel_mode()
&& elf_helpers::is_linux_kernel(elf_handle()));
if (looking_at_linux_kernel_binary)
{
if (s->is_in_ksymtab())
return s;
}
else
if (looking_at_linux_kernel_binary)
{
if (s->is_in_ksymtab())
return s;
}
else
return s;
}
return elf_symbol_sptr();
}
/// Test if a name is the name of an undefined function symbol.
///
/// @param name the symbol name to consider.
///
/// @return the undefined function symbol or nil if none was found.
elf_symbol_sptr
reader::function_symbol_is_undefined(const string& name) const
{return symtab()->function_symbol_is_undefined(name);}
/// Test if a name is the name of an undefined variable symbol.
///
/// @param name the symbol name to consider.
///
/// @return the undefined variable symbol or nil if none was found.
elf_symbol_sptr
reader::variable_symbol_is_undefined(const string& name) const
{return symtab()->variable_symbol_is_undefined(name);}
/// Load the DT_NEEDED and DT_SONAME elf TAGS.
void
reader::load_dt_soname_and_needed()
@@ -1061,7 +964,9 @@ get_type_of_elf_file(const string& path, elf::elf_type& type)
return false;
elf_version (EV_CURRENT);
Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
// Note that the dwelf_elf_begin function supports decompressing the
// content of the input file, which is pretty cool.
Elf *elf = dwelf_elf_begin(fd);
type = elf_file_type(elf);
elf_end(elf);
close(fd);
+36 -10
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2022-2023 Red Hat, Inc.
// Copyright (C) 2022-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -46,7 +46,6 @@ struct fe_iface::priv
corpus_path.clear();
dt_soname.clear();
suppressions.clear();
corpus_group.reset();
corpus.reset();
}
}; //end struct fe_iface::priv
@@ -297,30 +296,57 @@ fe_iface::should_reuse_type_from_corpus_group()
return corpus_sptr();
}
/// Try and add the representation of the ABI of a function to the set
/// of exported declarations of the current corpus.
/// Add the representation of the ABI of a function to the set of
/// exported declarations or undefined declarations of the current
/// corpus.
///
/// Note that if the function is defined and exported, then it's going
/// to be added to the set of functions exported by the current
/// corpus. Otherwise, if the function has an undefined symbol then
/// it's going to be added to the sef of undefined functions used by
/// the current corpus.
///
/// @param fn the internal representation of the ABI of a function.
void
fe_iface::maybe_add_fn_to_exported_decls(const function_decl* fn)
fe_iface::add_fn_to_exported_or_undefined_decls(const function_decl* fn)
{
bool added = false;
if (fn)
if (corpus::exported_decls_builder* b =
corpus()->get_exported_decls_builder().get())
b->maybe_add_fn_to_exported_fns(const_cast<function_decl*>(fn));
added = b->maybe_add_fn_to_exported_fns(const_cast<function_decl*>(fn));
if (fn && !added)
{
if (!fn->get_symbol() || !fn->get_symbol()->is_defined())
corpus()->get_undefined_functions().insert(fn);
}
}
/// Try and add the representation of the ABI of a variable to the set
/// of exported declarations of the current corpus.
/// Add the representation of the ABI of a variable to the set of
/// exported or undefined declarations of the current corpus.
///
/// Note that if the variable is defined and exported, then it's going
/// to be added to the set of variables exported by the current
/// corpus. Otherwise, if the variable has an undefined symbol then
/// it's going to be added to the sef of undefined variables used by
/// the current corpus.
///
/// @param var the internal representation of the ABI of a variable.
void
fe_iface::maybe_add_var_to_exported_decls(const var_decl* var)
fe_iface::add_var_to_exported_or_undefined_decls(const var_decl_sptr& var)
{
bool added = false;
if (var)
if (corpus::exported_decls_builder* b =
corpus()->get_exported_decls_builder().get())
b->maybe_add_var_to_exported_vars(var);
added = b->maybe_add_var_to_exported_vars(var);
if (var && !added)
{
if (!var->get_symbol() || !var->get_symbol()->is_defined())
corpus()->get_undefined_variables().insert(var);
}
}
/// The bitwise OR operator for the @ref fe_iface::status type.
+983 -777
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2016-2023 Red Hat, Inc.
// Copyright (C) 2016-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
+972 -671
View File
File diff suppressed because it is too large Load Diff
+3876 -1445
View File
File diff suppressed because it is too large Load Diff
+111 -130
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2017-2023 Red Hat, Inc.
// Copyright (C) 2017-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -256,6 +256,21 @@ leaf_reporter::report(const reference_diff& d,
report_local_reference_type_changes(d, out, indent);
}
/// Report the changes carried by a @ref ptr_to_mbr_diff node.
///
/// @param out the output stream to report to.
///
/// @param indent the white space string to use for indentation.
void
leaf_reporter::report(const ptr_to_mbr_diff& d, std::ostream& out,
const std::string& indent) const
{
if (!diff_to_be_reported(&d))
return;
report_local_ptr_to_mbr_type_changes(d, out, indent);
}
/// Report the changes carried by a @ref fn_parm_diff node.
///
/// @param out the output stream to report to.
@@ -659,15 +674,21 @@ leaf_reporter::report(const class_or_union_diff& d,
}
// report changes
size_t numchanges = (d.sorted_changed_data_members().size()
+ d.sorted_subtype_changed_data_members().size());
size_t net_numchanges = 0;
size_t num_filtered =
(d.count_filtered_changed_data_members(/*local_only=*/true)
+ d.count_filtered_subtype_changed_data_members(/*local_only=*/true));
for (var_diff_sptrs_type::const_iterator it =
d.sorted_changed_data_members().begin();
it != d.sorted_changed_data_members().end();
++it)
if (diff_to_be_reported((*it).get()))
net_numchanges++;
ABG_ASSERT(numchanges >= num_filtered);
size_t net_numchanges = numchanges - num_filtered;
for (var_diff_sptrs_type::const_iterator it =
d.sorted_subtype_changed_data_members().begin();
it != d.sorted_subtype_changed_data_members().end();
++it)
if (diff_to_be_reported((*it).get()))
net_numchanges++;
if (net_numchanges)
{
@@ -1059,32 +1080,29 @@ leaf_reporter::report(const corpus_diff& d,
out << indent << s.net_num_func_removed() << " Removed functions:\n\n";
bool emitted = false;
vector<function_decl*>sorted_deleted_fns;
corpus::functions sorted_deleted_fns;
sort_string_function_ptr_map(d.priv_->deleted_fns_, sorted_deleted_fns);
for (vector<function_decl*>::const_iterator i =
sorted_deleted_fns.begin();
i != sorted_deleted_fns.end();
++i)
for (auto f : sorted_deleted_fns)
{
if (d.priv_->deleted_function_is_suppressed(*i))
if (d.priv_->deleted_function_is_suppressed(f))
continue;
out << indent
<< " ";
out << "[D] ";
out << "'" << (*i)->get_pretty_representation() << "'";
out << "'" << f->get_pretty_representation() << "'";
if (ctxt->show_linkage_names())
{
out << " {";
show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
show_linkage_name_and_aliases(out, "", *f->get_symbol(),
d.first_corpus()->get_fun_symbol_map());
out << "}";
}
out << "\n";
if (is_member_function(*i) && get_member_function_is_virtual(*i))
if (is_member_function(f) && get_member_function_is_virtual(f))
{
class_decl_sptr c =
is_class_type(is_method_type((*i)->get_type())->get_class_type());
is_class_type(is_method_type(f->get_type())->get_class_type());
out << indent
<< " "
<< "note that this removes an entry from the vtable of "
@@ -1097,6 +1115,21 @@ leaf_reporter::report(const corpus_diff& d,
out << "\n";
}
if (size_t num_changed = s.num_leaf_func_with_incompatible_changes())
{
if (num_changed == 1)
out << indent << "1 function with incompatible sub-type changes: \n\n";
else if (num_changed > 1)
out << indent << num_changed
<< "functions with incompatible sub-type changes:\n\n";
sort_function_decl_diffs(const_cast<corpus_diff&>(d).
incompatible_changed_functions());
for (auto& fn_diff : d.incompatible_changed_functions())
if (fn_diff && fn_diff->has_local_changes())
emit_changed_fn_report(ctxt, fn_diff, out, indent);
}
if (ctxt->show_added_fns())
{
if (s.net_num_func_added() == 1)
@@ -1105,13 +1138,11 @@ leaf_reporter::report(const corpus_diff& d,
out << indent << s.net_num_func_added()
<< " Added functions:\n\n";
bool emitted = false;
vector<function_decl*> sorted_added_fns;
corpus::functions sorted_added_fns;
sort_string_function_ptr_map(d.priv_->added_fns_, sorted_added_fns);
for (vector<function_decl*>::const_iterator i = sorted_added_fns.begin();
i != sorted_added_fns.end();
++i)
for (auto f : sorted_added_fns)
{
if (d.priv_->added_function_is_suppressed(*i))
if (d.priv_->added_function_is_suppressed(f))
continue;
out
@@ -1119,21 +1150,21 @@ leaf_reporter::report(const corpus_diff& d,
<< " ";
out << "[A] ";
out << "'"
<< (*i)->get_pretty_representation()
<< f->get_pretty_representation()
<< "'";
if (ctxt->show_linkage_names())
{
out << " {";
show_linkage_name_and_aliases
(out, "", *(*i)->get_symbol(),
(out, "", *f->get_symbol(),
d.second_corpus()->get_fun_symbol_map());
out << "}";
}
out << "\n";
if (is_member_function(*i) && get_member_function_is_virtual(*i))
if (is_member_function(f) && get_member_function_is_virtual(f))
{
class_decl_sptr c =
is_class_type(is_method_type((*i)->get_type())->get_class_type());
is_class_type(is_method_type(f->get_type())->get_class_type());
out << indent
<< " "
<< "note that this adds a new entry to the vtable of "
@@ -1148,67 +1179,27 @@ leaf_reporter::report(const corpus_diff& d,
if (ctxt->show_changed_fns())
{
// Show changed functions.
size_t num_changed = s.net_num_leaf_func_changes();
if (num_changed == 1)
out << indent << "1 function with some sub-type change:\n\n";
else if (num_changed > 1)
out << indent << num_changed
<< " functions with some sub-type change:\n\n";
vector<function_decl_diff_sptr> sorted_changed_fns;
sort_string_function_decl_diff_sptr_map(d.priv_->changed_fns_map_,
sorted_changed_fns);
for (vector<function_decl_diff_sptr>::const_iterator i =
sorted_changed_fns.begin();
i != sorted_changed_fns.end();
++i)
if (size_t num_changed = s.net_num_leaf_func_non_incompatible_changes())
{
diff_sptr diff = *i;
if (!diff)
continue;
// Show changed functions.
if (num_changed == 1)
out << indent << "1 function with some sub-type change:\n\n";
else if (num_changed > 1)
out << indent << num_changed
<< " functions with some sub-type change:\n\n";
if (diff_to_be_reported(diff.get()))
vector<function_decl_diff_sptr> sorted_changed_fns;
sort_string_function_decl_diff_sptr_map(d.priv_->changed_fns_map_,
sorted_changed_fns);
for (vector<function_decl_diff_sptr>::const_iterator i =
sorted_changed_fns.begin();
i != sorted_changed_fns.end();
++i)
{
function_decl_sptr fn = (*i)->first_function_decl();
out << indent << " [C] '"
<< fn->get_pretty_representation() << "'";
report_loc_info((*i)->second_function_decl(), *ctxt, out);
out << " has some sub-type changes:\n";
if ((fn->get_symbol()->has_aliases()
&& !(is_member_function(fn)
&& get_member_function_is_ctor(fn))
&& !(is_member_function(fn)
&& get_member_function_is_dtor(fn)))
|| (is_c_language(get_translation_unit(fn)->get_language())
&& fn->get_name() != fn->get_linkage_name()))
{
int number_of_aliases =
fn->get_symbol()->get_number_of_aliases();
if (number_of_aliases == 0)
{
out << indent << " "
<< "Please note that the exported symbol of "
"this function is "
<< fn->get_symbol()->get_id_string()
<< "\n";
}
else
{
out << indent << " "
<< "Please note that the symbol of this function is "
<< fn->get_symbol()->get_id_string()
<< "\n and it aliases symbol";
if (number_of_aliases > 1)
out << "s";
out << ": "
<< fn->get_symbol()->get_aliases_id_string(false)
<< "\n";
}
}
diff->report(out, indent + " ");
// Extra spacing.
out << "\n";
function_decl_diff_sptr fn_diff = *i;
if (fn_diff
&& !filtering::has_incompatible_fn_or_var_change(fn_diff))
emit_changed_fn_report(ctxt, fn_diff, out, indent);
}
}
// Changed functions have extra spacing already. No new line here.
@@ -1224,17 +1215,14 @@ leaf_reporter::report(const corpus_diff& d,
<< " Removed variables:\n\n";
string n;
bool emitted = false;
vector<var_decl*> sorted_deleted_vars;
corpus::variables sorted_deleted_vars;
sort_string_var_ptr_map(d.priv_->deleted_vars_, sorted_deleted_vars);
for (vector<var_decl*>::const_iterator i =
sorted_deleted_vars.begin();
i != sorted_deleted_vars.end();
++i)
for (auto v : sorted_deleted_vars)
{
if (d.priv_->deleted_variable_is_suppressed(*i))
if (d.priv_->deleted_variable_is_suppressed(v))
continue;
n = (*i)->get_pretty_representation();
n = v->get_pretty_representation();
out << indent
<< " ";
@@ -1245,7 +1233,7 @@ leaf_reporter::report(const corpus_diff& d,
if (ctxt->show_linkage_names())
{
out << " {";
show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
show_linkage_name_and_aliases(out, "", *v->get_symbol(),
d.first_corpus()->get_var_symbol_map());
out << "}";
}
@@ -1265,17 +1253,14 @@ leaf_reporter::report(const corpus_diff& d,
<< " Added variables:\n\n";
string n;
bool emitted = false;
vector<var_decl*> sorted_added_vars;
corpus::variables sorted_added_vars;
sort_string_var_ptr_map(d.priv_->added_vars_, sorted_added_vars);
for (vector<var_decl*>::const_iterator i =
sorted_added_vars.begin();
i != sorted_added_vars.end();
++i)
for (auto v : sorted_added_vars)
{
if (d.priv_->added_variable_is_suppressed(*i))
if (d.priv_->added_variable_is_suppressed(v))
continue;
n = (*i)->get_pretty_representation();
n = v->get_pretty_representation();
out << indent
<< " ";
@@ -1284,7 +1269,7 @@ leaf_reporter::report(const corpus_diff& d,
if (ctxt->show_linkage_names())
{
out << " {";
show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
show_linkage_name_and_aliases(out, "", *v->get_symbol(),
d.second_corpus()->get_var_symbol_map());
out << "}";
}
@@ -1297,38 +1282,34 @@ leaf_reporter::report(const corpus_diff& d,
if (ctxt->show_changed_vars())
{
size_t num_changed = s.net_num_leaf_var_changes();
if (num_changed == 1)
out << indent << "1 Changed variable:\n\n";
else if (num_changed > 1)
out << indent << num_changed
<< " Changed variables:\n\n";
string n1, n2;
for (var_diff_sptrs_type::const_iterator i =
d.priv_->sorted_changed_vars_.begin();
i != d.priv_->sorted_changed_vars_.end();
++i)
if (size_t num_changed = s.num_var_with_incompatible_changes())
{
diff_sptr diff = *i;
if (num_changed == 1)
out << indent << "1 variable with incompatible sub-type changes:\n\n";
else if (num_changed > 1)
out << indent << num_changed
<< " variables with incompatible sub-type changes:\n\n";
if (!diff)
continue;
if (!diff_to_be_reported(diff.get()))
continue;
n1 = diff->first_subject()->get_pretty_representation();
n2 = diff->second_subject()->get_pretty_representation();
out << indent << " [C] '" << n1 << "' was changed";
if (n1 != n2)
out << " to '" << n2 << "'";
report_loc_info(diff->second_subject(), *ctxt, out);
out << ":\n";
diff->report(out, indent + " ");
// Extra spacing.
out << "\n";
sort_var_diffs(const_cast<corpus_diff&>(d).
incompatible_changed_variables());
for (auto& var_diff : d.incompatible_changed_variables())
if (var_diff)
emit_changed_var_report(ctxt, var_diff, out, indent);
}
if (size_t num_changed = s.net_num_leaf_var_non_incompatible_changes())
{
if (num_changed == 1)
out << indent << "1 Changed variable:\n\n";
else if (num_changed > 1)
out << indent << num_changed
<< " Changed variables:\n\n";
string n1, n2;
for (var_diff_sptr diff : d.priv_->sorted_changed_vars_)
if (diff && !filtering::has_incompatible_fn_or_var_change(diff))
emit_changed_var_report(ctxt, diff, out, indent);
}
// Changed variables have extra spacing already. No new line here.
}
+134 -1
View File
@@ -1,12 +1,14 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
#include <string>
#include <iostream>
#include <fstream>
#include "abg-tools-utils.h"
#include "abg-internal.h"
// <headers defining libabigail's API go under here>
@@ -43,6 +45,137 @@ build_sptr<xmlChar>(xmlChar *p)
namespace xml
{
using std::istream;
using std::ifstream;
using tools_utils::xz_decompressor_type;
using tools_utils::file_type;
using tools_utils::guess_file_type;
// <xmlIO callbacks for xz reading support>
/// This is an xmlIO callback function used in the libxml2 I/O input
/// API to detect if the current handler can provider input
/// functionality for a file designed by a path.
///
/// This function should return 1 iff the file contains XZ-compressed
/// data.
///
/// @param filepath the path to file to consider.
///
/// @return 1 iff the file designated by @p filepath is XZ-compressed.
static int
xz_io_match_cb(const char*filepath)
{
bool does_match = false;
file_type t = guess_file_type(filepath, /*look_through_compression=*/false);
if (t == tools_utils::FILE_TYPE_XZ)
does_match = true;
return does_match;
}
/// This is the context used by the xmlIO handler that provides input
/// functionality to the libxml2 I/O input API for XZ-compressed XML
/// files.
struct xz_ctxt_type
{
// The input XZ-compressed file stream.
std::unique_ptr<std::ifstream> input_fstream;
// The custom XZ-decompressor streambuf provided by tools-utils.
std::unique_ptr<xz_decompressor_type> decompressor_streambuf;
// The decompressed input stream that we can read from.
std::unique_ptr<std::istream> decompressed_input_stream;
xz_ctxt_type() = delete;
/// Constructor.
///
/// @param is the XZ-compressed input file stream to consider.
xz_ctxt_type(std::ifstream* is)
: input_fstream(is),
decompressor_streambuf(new xz_decompressor_type(*is)),
decompressed_input_stream(new istream(decompressor_streambuf.get()))
{}
}; // end struct xz_ctxt_type.
/// Callback used in the I/O input API of libxml2 to open a file
/// designated by a path and containing XZ-compressed content.
///
/// @param filepath the path to the file to open. The file should
/// contain XZ-compressed data, as detected by @ref xz_io_match_cb.
///
/// @return a pointer to an instance of @ref xz_ctxt_type if the
/// function could successfully open the file denoted by @p filepath.
/// Please note that this instance of @ref xz_ctxt_type has to be
/// deleted by @ref xz_io_close_cb.
static void*
xz_io_open_cb(const char* filepath)
{
std::ifstream* s = new std::ifstream(filepath, ifstream::binary);
if (s->bad())
{
delete s;
return nullptr;
}
xz_ctxt_type *ctxt = new xz_ctxt_type(s);
return ctxt;
}
/// Callback used in the I/O input API of libxml2 to read and
/// decompress data from an XZ-compressed file previously opened by
/// @ref xz_io_open_cb.
///
/// @param context a pointer to the instance of @ref xz_ctxt_type
/// returned by @ref xz_io_open_cb. That context is used to read and
/// decompress the XZ-compressed data coming from input file.
///
/// @param buffer the buffer where to copy the XZ-decompressed data.
///
/// @param len the length of @p buffer.
///
/// @return the actual number of bytes decompressed and copied into @p
/// buffer.
static int
xz_io_read_cb(void* context, char *buffer, int len)
{
xz_ctxt_type *ctxt = static_cast<xz_ctxt_type *>(context);
ctxt->decompressed_input_stream->read(buffer, len);
int nb_bytes_read = ctxt->decompressed_input_stream->gcount();
return nb_bytes_read;
}
/// Callback used in the I/O input API of libxml2 to delete the
/// instance of @ref xz_ctxt_type created by @ref xz_io_open_cb and
/// free its associated resources.
///
/// @param context the pointer to the instance of @ref xz_ctxt_type to
/// delete.
///
/// @return 0 iff the operation was successful.
static int
xz_io_close_cb(void* context)
{
xz_ctxt_type *ctxt = static_cast<xz_ctxt_type*>(context);
ctxt->decompressed_input_stream.reset();
ctxt->input_fstream->close();
ctxt->input_fstream.reset();
delete ctxt;
return 0;
}
// </xmlIO callbacks for xz reading support>
/// The initialization function of libxml2 abstraction layer. This
/// function must be called prior to using any of the libxml2 capabilities.
void
initialize()
{
LIBXML_TEST_VERSION;
xmlInitParser();
xmlRegisterInputCallbacks(xz_io_match_cb, xz_io_open_cb,
xz_io_read_cb, xz_io_close_cb);
}
/// Instantiate an xmlTextReader that parses the content of an on-disk
/// file, wrap it into a smart pointer and return it.
+863 -217
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2016-2023 Red Hat, Inc.
// Copyright (C) 2016-2025 Red Hat, Inc.
/// @file
///
+151 -14
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2017-2023 Red Hat, Inc.
// Copyright (C) 2017-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -544,7 +544,7 @@ represent(const var_diff_sptr &diff,
if (!filtering::has_anonymous_data_member_change(diff) && o_name != n_name)
{
if (filtering::has_harmless_name_change(o, n)
if (filtering::has_harmless_name_change(o, n, ctxt)
&& !(ctxt->get_allowed_category()
& HARMLESS_DECL_NAME_CHANGE_CATEGORY))
;
@@ -746,7 +746,7 @@ represent(const subrange_diff& d,
int64_t oub = o->get_upper_bound();
int64_t nub = n->get_upper_bound();
if (on != nn)
if (on != nn)
{
out << indent << "name of range changed from '"
<< on << "' to '" << nn << "'\n";
@@ -754,9 +754,7 @@ represent(const subrange_diff& d,
if (olb != nlb)
{
out << indent << "lower bound of range '"
<< on
<< "' change from '";
out << indent << "lower bound of '" << oor << "' change from '";
emit_num_value(olb, *ctxt, out);
out << "' to '";
emit_num_value(nlb, *ctxt, out);
@@ -765,15 +763,30 @@ represent(const subrange_diff& d,
if (oub != nub)
{
out << indent << "upper bound of range '"
<< on
<< "' change from '";
out << indent << "upper bound of '" << oor << "' change from '";
emit_num_value(oub, *ctxt, out);
out << "' to '";
emit_num_value(nub, *ctxt, out);
out << "'\n";
}
if (o->is_non_finite() != n->is_non_finite())
{
out << indent
<< (o->is_non_finite()
? string("unknown sized")
: string("known sized"))
<< string(" range '")
<< oor
<< string("' changed to ")
<< (n->is_non_finite()
? string("unknown sized")
: string("known sized"))
<< string(" range '")
<< nr
<< "'\n";
}
if (!local_only)
{
diff_sptr dif = d.underlying_type_diff();
@@ -837,12 +850,12 @@ report_size_and_alignment_changes(type_or_decl_base_sptr first,
// We are looking at size or alignment changes between two
// arrays ...
out << indent << "array type size changed from ";
if (first_array->is_infinite())
if (first_array->is_non_finite())
out << "\'unknown\'";
else
emit_num_value(first_array->get_size_in_bits(), *ctxt, out);
out << " to ";
if (second_array->is_infinite())
if (second_array->is_non_finite())
out << "\'unknown\'";
else
emit_num_value(second_array->get_size_in_bits(), *ctxt, out);
@@ -871,14 +884,14 @@ report_size_and_alignment_changes(type_or_decl_base_sptr first,
<< i - first_array->get_subranges().begin() + 1
<< " changed length from ";
if ((*i)->is_infinite())
if ((*i)->is_non_finite())
out << "\'unknown\'";
else
out << (*i)->get_length();
out << " to ";
if ((*j)->is_infinite())
if ((*j)->is_non_finite())
out << "\'unknown\'";
else
out << (*j)->get_length();
@@ -973,7 +986,7 @@ report_name_size_and_alignment_changes(decl_base_sptr first,
&& fn != sn)
{
if (!(ctxt->get_allowed_category() & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
&& filtering::has_harmless_name_change(first, second))
&& filtering::has_harmless_name_change(first, second, ctxt))
// This is a harmless name change. but then
// HARMLESS_DECL_NAME_CHANGE_CATEGORY doesn't seem allowed.
;
@@ -1092,6 +1105,130 @@ report_mem_header(ostream& out,
out << indent << "there are " << section_name << " " << change << ":\n";
}
/// Emit a report about a changed function.
///
/// @param ctxt the diff context to use for the report.
///
/// @param fn_diff the function_diff node to emit the report for.
///
/// @param out the output stream to emit the report to.
///
/// @param indent the indentation string to use.
///
/// @param indirect_changed_subtypes if true, this means there are
/// indirect sub-types changes. Indirect means it's a pointed-to-type
/// that changed.
///
/// @param emit_redundant_fn_changes if true, the function reports
/// about changes carried by @fn_diff even if they are redundant.
void
emit_changed_fn_report(const diff_context_sptr& ctxt,
const function_decl_diff_sptr& fn_diff,
ostream& out, const string indent,
bool indirect_changed_subtypes,
bool emit_redundant_fn_changes)
{
bool saved_show_redundant_changes = ctxt->show_redundant_changes();
ctxt->show_redundant_changes(emit_redundant_fn_changes);
if (fn_diff->to_be_reported())
{
function_decl_sptr fn = fn_diff->first_function_decl();
out << indent << " [C] '"
<< fn->get_pretty_representation() << "'";
report_loc_info(fn_diff->first_function_decl(), *ctxt, out);
out << " has some";
if (indirect_changed_subtypes)
out << " indirect";
out << " sub-type changes:\n";
if ((fn->get_symbol()->has_aliases()
&& !(is_member_function(fn)
&& get_member_function_is_ctor(fn))
&& !(is_member_function(fn)
&& get_member_function_is_dtor(fn)))
|| (is_c_language(get_translation_unit(fn)->get_language())
&& fn->get_name() != fn->get_linkage_name()))
{
int number_of_aliases =
fn->get_symbol()->get_number_of_aliases();
if (number_of_aliases == 0)
{
out << indent << " "
<< "Please note that the exported symbol of "
"this function is "
<< fn->get_symbol()->get_id_string()
<< "\n";
}
else
{
out << indent << " "
<< "Please note that the symbol of this function is "
<< fn->get_symbol()->get_id_string()
<< "\n and it aliases symbol";
if (number_of_aliases > 1)
out << "s";
out << ": "
<< fn->get_symbol()->get_aliases_id_string(false)
<< "\n";
}
}
fn_diff->report(out, indent + " ");
// Extra spacing.
out << "\n";
}
ctxt->show_redundant_changes(saved_show_redundant_changes);
}
/// Emit a report about a changed variable.
///
/// @param ctxt the diff context to use for the report.
///
/// @param fn_diff the var_diff node to emit the report for.
///
/// @param out the output stream to emit the report to.
///
/// @param indent the indentation string to use.
///
/// @param indirect_changed_subtypes if true, this means there are
/// indirect sub-types changes. Indirect means it's a pointed-to-type
/// that changed.
///
/// @param emit_redundant_var_changes if true, the function reports
/// about changes carried by @fn_diff even if they are redundant.
void
emit_changed_var_report(const diff_context_sptr& ctxt,
const var_diff_sptr& var_diff,
ostream& out, const string indent,
bool emit_redundant_var_changes)
{
diff_sptr diff = var_diff;
if (!diff)
return;
bool saved_show_redundant_changes = ctxt->show_redundant_changes();
ctxt->show_redundant_changes(emit_redundant_var_changes);
if (diff->to_be_reported())
{
string n1 = diff->first_subject()->get_pretty_representation();
string n2 = diff->second_subject()->get_pretty_representation();
out << indent << " [C] '" << n1 << "' was changed";
if (n1 != n2)
out << " to '" << n2 << "'";
report_loc_info(diff->second_subject(), *ctxt, out);
out << ":\n";
diff->report(out, indent + " ");
// Extra spacing.
out << "\n";
}
ctxt->show_redundant_changes(saved_show_redundant_changes);
}
/// Report the differences in access specifiers and static-ness for
/// class members.
///
+14 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -206,6 +206,19 @@ report_mem_header(ostream& out,
const string& section_name,
const string& indent);
void
emit_changed_fn_report(const diff_context_sptr& ctxt,
const function_decl_diff_sptr& fn_diff,
ostream& out, const string indent,
bool indirect_changed_subtypes = false,
bool emit_redundant_fn_changes = true);
void
emit_changed_var_report(const diff_context_sptr& ctxt,
const var_diff_sptr& var_diff,
ostream& out, const string indent,
bool emit_redundant_var_changes = true);
bool
maybe_report_diff_for_member(const decl_base_sptr& decl1,
const decl_base_sptr& decl2,
+6 -2
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2016-2023 Red Hat, Inc.
// Copyright (C) 2016-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -586,6 +586,9 @@ class type_suppression::priv
mutable regex::regex_t_sptr source_location_to_keep_regex_;
mutable vector<string> changed_enumerator_names_;
mutable vector<regex::regex_t_sptr> changed_enumerators_regexp_;
// Whether the "has_strict_flexible_array_data_member_conversion"
// property was set.
bool has_strict_fam_conv_;
priv();
@@ -602,7 +605,8 @@ public:
type_kind_(type_kind),
consider_reach_kind_(consider_reach_kind),
reach_kind_(reach_kind),
has_size_change_(false)
has_size_change_(false),
has_strict_fam_conv_(false)
{}
/// Get the regular expression object associated to the 'type_name_regex'
+65 -23
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2016-2023 Red Hat, Inc.
// Copyright (C) 2016-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
@@ -808,6 +808,21 @@ void
type_suppression::set_changed_enumerators_regexp(const vector<regex::regex_t_sptr>& n)
{priv_->changed_enumerators_regexp_ = n;}
/// Getter of the "has_string_fam_conversion" property.
///
/// @return the value of the "has_string_fam_conversion" property.
bool
type_suppression::has_strict_fam_conversion () const
{return priv_->has_strict_fam_conv_;}
/// Setter of the "has_string_fam_conversion" property.
///
/// @param f the new value of the "has_string_fam_conversion"
/// property.
void
type_suppression::set_has_strict_fam_conversion(bool f)
{priv_->has_strict_fam_conv_ = f;}
/// Evaluate this suppression specification on a given diff node and
/// say if the diff node should be suppressed or not.
///
@@ -911,7 +926,7 @@ type_suppression::suppresses_diff(const diff* diff) const
// public -- depending on, e.g, if the typedef is defined in a
// public header or not. So if we are in the context of a
// private type suppression let's *NOT* peel typedefs away.
if (!is_private_type_suppr_spec(*this))
if (!is_opaque_type_suppr_spec(*this))
{
ft = peel_typedef_type(ft);
st = peel_typedef_type(st);
@@ -967,6 +982,11 @@ type_suppression::suppresses_diff(const diff* diff) const
const class_diff* klass_diff = dynamic_cast<const class_diff*>(d);
if (klass_diff)
{
const class_decl_sptr& first_class =
klass_diff->first_class_decl();
const class_decl_sptr& second_class =
klass_diff->second_class_decl();
// We are looking at a class diff ...
if (!get_data_member_insertion_ranges().empty())
{
@@ -981,9 +1001,6 @@ type_suppression::suppresses_diff(const diff* diff) const
// that suppression applies to types that have size
// change.
const class_decl_sptr& first_type_decl =
klass_diff->first_class_decl();
if (klass_diff->inserted_data_members().empty()
&& klass_diff->changed_data_members().empty())
// So there is a has_data_member_inserted_* clause,
@@ -1001,7 +1018,7 @@ type_suppression::suppresses_diff(const diff* diff) const
for (const auto& range : get_data_member_insertion_ranges())
if (is_data_member_offset_in_range(is_var_decl(member),
range,
first_type_decl.get()))
first_class.get()))
matched = true;
if (!matched)
@@ -1017,7 +1034,7 @@ type_suppression::suppresses_diff(const diff* diff) const
for (const auto& range : get_data_member_insertion_ranges())
if (is_data_member_offset_in_range(member, range,
first_type_decl.get()))
first_class.get()))
matched = true;
if (!matched)
@@ -1027,6 +1044,20 @@ type_suppression::suppresses_diff(const diff* diff) const
else
return false;
}
// Support for the
// "has_strict_flexible_array_data_member_conversion = true"
// clause.
if (has_strict_fam_conversion())
{
// Let's detect if the first class of the diff has a fake
// flexible array data member that got turned into a real
// flexible array data member.
if (!((get_has_size_change() || ((first_class->get_size_in_bits()
== second_class->get_size_in_bits())))
&& filtering::has_strict_fam_conversion(klass_diff)))
return false;
}
}
const enum_diff* enum_dif = dynamic_cast<const enum_diff*>(d);
@@ -1315,7 +1346,7 @@ suppression_matches_type_location(const type_suppression& s,
// the declaration. If we reach this place, it
// means the class has no definition at this point.
ABG_ASSERT(!cl->get_definition_of_declaration());
if (s.get_label() == get_private_types_suppr_spec_label())
if (s.get_label() == get_opaque_types_suppr_spec_label())
// So this looks like what really amounts to an
// opaque type. So it's not defined in the public
// headers. So we want to filter it out.
@@ -2321,6 +2352,14 @@ read_type_suppression(const ini::config::section& section)
}
}
// Support "has_strict_flexible_array_data_member_conversion"
ini::simple_property_sptr has_strict_fam_conv =
is_simple_property
(section.find_property("has_strict_flexible_array_data_member_conversion"));
string has_strict_fam_conv_str = has_strict_fam_conv
? has_strict_fam_conv->get_value()->as_string()
: "";
if (section.get_name() == "suppress_type")
result.reset(new type_suppression(label_str, name_regex_str, name_str));
else if (section.get_name() == "allow_type")
@@ -2388,6 +2427,9 @@ read_type_suppression(const ini::config::section& section)
&& !changed_enumerators_regexp.empty())
result->set_changed_enumerators_regexp(changed_enumerators_regexp);
if (has_strict_fam_conv_str == "yes" || has_strict_fam_conv_str == "true")
result->set_has_strict_fam_conversion(true);
return result;
}
@@ -3244,7 +3286,7 @@ function_suppression::suppresses_function_symbol(const elf_symbol* sym,
return false;
ABG_ASSERT(k & function_suppression::ADDED_FUNCTION_CHANGE_KIND
|| k & function_suppression::DELETED_FUNCTION_CHANGE_KIND);
|| k & function_suppression::DELETED_FUNCTION_CHANGE_KIND);
// Check if the name and soname of the binaries match the current
// suppr spect
@@ -4868,12 +4910,12 @@ suppression_matches_soname_or_filename(const string& soname,
/// specification that is auto-generated by libabigail to suppress
/// change reports about types that are not defined in public headers.
const char*
get_private_types_suppr_spec_label()
get_opaque_types_suppr_spec_label()
{
static const char *PRIVATE_TYPES_SUPPR_SPEC_NAME =
"Artificial private types suppression specification";
static const char *OPAQUE_TYPES_SUPPR_SPEC_NAME =
"libabigail::OPAQUE_TYPE_LABEL";
return PRIVATE_TYPES_SUPPR_SPEC_NAME;
return OPAQUE_TYPES_SUPPR_SPEC_NAME;
}
/// Test if a type suppression specification represents a private type
@@ -4884,8 +4926,8 @@ get_private_types_suppr_spec_label()
///
/// @return true iff @p s is a private type suppr spec.
bool
is_private_type_suppr_spec(const type_suppression& s)
{return s.get_label() == get_private_types_suppr_spec_label();}
is_opaque_type_suppr_spec(const type_suppression& s)
{return s.get_label() == get_opaque_types_suppr_spec_label();}
/// Test if a type suppression specification represents a private type
/// suppression automatically generated by libabigail from the user
@@ -4895,11 +4937,11 @@ is_private_type_suppr_spec(const type_suppression& s)
///
/// @return true iff @p s is a private type suppr spec.
bool
is_private_type_suppr_spec(const suppression_sptr& s)
is_opaque_type_suppr_spec(const suppression_sptr& s)
{
type_suppression_sptr type_suppr = is_type_suppression(s);
return (type_suppr
&& type_suppr->get_label() == get_private_types_suppr_spec_label());
&& type_suppr->get_label() == get_opaque_types_suppr_spec_label());
}
// </file_suppression stuff>
@@ -5233,9 +5275,9 @@ is_variable_suppressed(const fe_iface& fe,
///
/// @param type_location the source location of the type.
///
/// @param type_is_private output parameter. This is set to true if
/// @param type_is_opaque output parameter. This is set to true if
/// the type was matched by one suppression specification, and if the
/// suppression was for private types.
/// suppression was for opaque types.
///
/// @param require_drop_property if true, this type requires the
/// suppression specification to contain the "drop" property to match
@@ -5247,7 +5289,7 @@ bool
is_type_suppressed(const fe_iface& fe,
const string& type_name,
const location& type_location,
bool& type_is_private,
bool& type_is_opaque,
bool require_drop_property)
{
for (auto i : fe.suppressions())
@@ -5259,14 +5301,14 @@ is_type_suppressed(const fe_iface& fe,
type_name,
type_location))
{
if (is_private_type_suppr_spec(*suppr))
type_is_private = true;
if (is_opaque_type_suppr_spec(*suppr))
type_is_opaque = true;
return true;
}
}
type_is_private = false;
type_is_opaque = false;
return false;
}
+237 -13
View File
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2020-2023 Google, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
// Copyright (C) 2020-2025 Google, Inc.
//
// Author: Matthias Maennich
@@ -115,6 +115,184 @@ symtab::lookup_symbol(GElf_Addr symbol_addr) const
return empty_result;
}
/// Lookup an undefined function symbol with a given name.
///
/// @param sym_name the name of the function symbol to lookup.
///
/// @return the undefined function symbol found or nil if none was
/// found.
const elf_symbol_sptr
symtab::lookup_undefined_function_symbol(const std::string& sym_name)
{
symtab_filter f = make_filter();
f.set_variables(false);
f.set_public_symbols(false);
f.set_functions(true);
f.set_undefined_symbols(true);
elf_symbol_sptr result;
for (auto sym : filtered_symtab(*this, f))
if (sym_name == sym->get_name())
{
result = sym;
break;
}
return result;
}
/// Lookup an undefined variable symbol with a given name.
///
/// @param sym_name the name of the variable symbol to lookup.
///
/// @return the undefined variable symbol found or nil if none was
/// found.
const elf_symbol_sptr
symtab::lookup_undefined_variable_symbol(const std::string& sym_name)
{
symtab_filter f = make_filter();
f.set_functions(false);
f.set_public_symbols(false);
f.set_undefined_symbols(true);
f.set_variables(true);
elf_symbol_sptr result;
for (auto sym : filtered_symtab(*this, f))
if (sym_name == sym->get_name())
{
result = sym;
break;
}
return result;
}
/// Test if a given function symbol has been exported.
///
/// Note that this doesn't test if the symbol is defined or not, but
/// assumes the symbol is defined.
///
/// @param name the name of the symbol we are looking for.
///
/// @return the elf symbol if found, or nil otherwise.
elf_symbol_sptr
symtab::function_symbol_is_exported(const string& name)
{
const elf_symbols& syms = lookup_symbol(name);
for (auto s : syms)
if (s->is_function() && s->is_public())
return s;
return elf_symbol_sptr();
}
/// Test if a given function symbol has been exported.
///
/// Note that this doesn't test if the symbol is defined or not, but
/// assumes the symbol is defined.
///
/// @param symbol_address the address of the symbol we are looking
/// for. Note that this address must be a relative offset from the
/// beginning of the .text section, just like the kind of addresses
/// that are present in the .symtab section.
///
/// @return the elf symbol if found, or nil otherwise.
elf_symbol_sptr
symtab::function_symbol_is_exported(const GElf_Addr symbol_address)
{
elf_symbol_sptr symbol = lookup_symbol(symbol_address);
if (!symbol)
return symbol;
if (!symbol->is_function() || !symbol->is_public())
return elf_symbol_sptr();
return symbol;
}
/// Test if a given variable symbol has been exported.
///
/// Note that this assumes the symbol is exported but doesn't test for
/// it.
///
/// @param name the name of the symbol we are looking
/// for.
///
/// @return the elf symbol if found, or nil otherwise.
elf_symbol_sptr
symtab::variable_symbol_is_exported(const string& name)
{
const elf_symbols& syms = lookup_symbol(name);
for (auto s : syms)
if (s->is_variable() && s->is_public())
return s;
return elf_symbol_sptr();
}
/// Test if a given variable symbol has been exported.
///
/// Note that this assumes the symbol is exported but doesn't test for
/// it.
///
/// @param symbol_address the address of the symbol we are looking
/// for. Note that this address must be a relative offset from the
/// beginning of the .text section, just like the kind of addresses
/// that are present in the .symtab section.
///
/// @return the elf symbol if found, or nil otherwise.
elf_symbol_sptr
symtab::variable_symbol_is_exported(const GElf_Addr symbol_address)
{
elf_symbol_sptr symbol = lookup_symbol(symbol_address);
if (!symbol)
return symbol;
if (!symbol->is_variable() || !symbol->is_public())
return elf_symbol_sptr();
return symbol;
}
/// Test if a name is a the name of an undefined function symbol.
///
/// @param sym_name the symbol name to consider.
///
/// @return the undefined symbol if found, nil otherwise.
elf_symbol_sptr
symtab::function_symbol_is_undefined(const string& sym_name)
{
collect_undefined_fns_and_vars_linkage_names();
if (undefined_function_linkage_names_.count(sym_name))
{
elf_symbol_sptr sym = lookup_undefined_function_symbol(sym_name);
ABG_ASSERT(sym);
ABG_ASSERT(sym->is_function());
ABG_ASSERT(!sym->is_defined());
return sym;
}
return elf_symbol_sptr();
}
/// Test if a name is a the name of an undefined variable symbol.
///
/// @param sym_name the symbol name to consider.
///
// @return the undefined symbol if found, nil otherwise.
elf_symbol_sptr
symtab::variable_symbol_is_undefined(const string& sym_name)
{
collect_undefined_fns_and_vars_linkage_names();
if (undefined_variable_linkage_names_.count(sym_name))
{
elf_symbol_sptr sym = lookup_undefined_variable_symbol(sym_name);
ABG_ASSERT(sym);
ABG_ASSERT(sym->is_variable());
ABG_ASSERT(!sym->is_defined());
return sym;
}
return elf_symbol_sptr();
}
/// A symbol sorting functor.
static struct
{
@@ -173,7 +351,8 @@ symtab::load(string_elf_symbols_map_sptr function_symbol_map,
/// Default constructor of the @ref symtab type.
symtab::symtab()
: is_kernel_binary_(false), has_ksymtab_entries_(false)
: is_kernel_binary_(false), has_ksymtab_entries_(false),
cached_undefined_symbol_names_(false)
{}
/// Load the symtab representation from an Elf binary presented to us by an
@@ -350,6 +529,9 @@ symtab::load_(Elf* elf_handle,
// section it refers to cannot be absolute.
// Otherwise that OBJECT is not a variable.
|| (sym_type == STT_OBJECT && sym->st_shndx != SHN_ABS)
// Undefined global variable symbols have symbol type
// STT_NOTYPE. No idea why.
|| (sym_type == STT_NOTYPE && sym->st_shndx == SHN_UNDEF)
|| sym_type == STT_TLS))
continue;
@@ -369,15 +551,6 @@ symtab::load_(Elf* elf_handle,
elf_helpers::stv_to_elf_symbol_visibility
(GELF_ST_VISIBILITY(sym->st_other)));
// We do not take suppressed symbols into our symbol vector to avoid
// accidental leakage. But we ensure supressed symbols are otherwise set
// up for lookup.
if (!(is_suppressed && is_suppressed(symbol_sptr)))
// add to the symbol vector
symbols_.push_back(symbol_sptr);
else
symbol_sptr->set_is_suppressed(true);
// add to the name->symbol lookup
name_symbol_map_[name].push_back(symbol_sptr);
@@ -401,6 +574,25 @@ symtab::load_(Elf* elf_handle,
setup_symbol_lookup_tables(elf_handle, sym, symbol_sptr);
}
// Now that symbols aliases have been constructed, let's determine
// what symbol has been suppressed or not. Suppression takes into
// account
for (auto& elem : name_symbol_map_)
{
auto& symbols = elem.second;
for (auto& symbol : symbols)
{
// We do not take suppressed symbols into our symbol vector
// to avoid accidental leakage. But we ensure supressed
// symbols are otherwise set up for lookup.
if (!(is_suppressed && is_suppressed(symbol)))
// add to the symbol vector
symbols_.push_back(symbol);
else
symbol->set_is_suppressed(true);
}
}
add_alternative_address_lookups(elf_handle);
is_kernel_binary_ = elf_helpers::is_linux_kernel(elf_handle);
@@ -524,7 +716,7 @@ symtab::update_main_symbol(GElf_Addr addr, const std::string& name)
/// Various adjustments and bookkeeping may be needed to provide a correct
/// interpretation (one that matches DWARF addresses) of raw symbol values.
///
/// This is a sub-routine for symtab::load_and
/// This is a sub-routine for symtab::load_ and
/// symtab::add_alternative_address_lookups and must be called only
/// once (per symbol) during the execution of the former.
///
@@ -736,5 +928,37 @@ symtab::add_alternative_address_lookups(Elf* elf_handle)
}
}
/// Collect the names of the variable and function symbols that are
/// undefined. Cache those names into sets to speed up their lookup.
///
/// Once the names are cached into sets, subsequent invocations of
/// this function are essentially a no-op.
void
symtab::collect_undefined_fns_and_vars_linkage_names()
{
if (!cached_undefined_symbol_names_)
{
{
symtab_filter f = make_filter();
f.set_variables(false);
f.set_functions(true);
f.set_public_symbols(false);
f.set_undefined_symbols(true);
for (auto sym : filtered_symtab(*this, f))
undefined_function_linkage_names_.insert(sym->get_name());
}
{
symtab_filter f = make_filter();
f.set_variables(true);
f.set_functions(false);
f.set_public_symbols(false);
f.set_undefined_symbols(true);
for (auto sym : filtered_symtab(*this, f))
undefined_variable_linkage_names_.insert(sym->get_name());
}
}
cached_undefined_symbol_names_ = true;
}
} // end namespace symtab_reader
} // end namespace abigail
+36 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2020-2023 Google, Inc.
// Copyright (C) 2020-2025 Google, Inc.
//
// Author: Matthias Maennich
@@ -242,6 +242,30 @@ public:
const elf_symbol_sptr&
lookup_symbol(GElf_Addr symbol_addr) const;
const elf_symbol_sptr
lookup_undefined_function_symbol(const std::string& name);
const elf_symbol_sptr
lookup_undefined_variable_symbol(const std::string& name);
elf_symbol_sptr
function_symbol_is_exported(const string&);
elf_symbol_sptr
function_symbol_is_exported(const GElf_Addr symbol_address);
elf_symbol_sptr
variable_symbol_is_exported(const string&);
elf_symbol_sptr
variable_symbol_is_exported(const GElf_Addr symbol_address);
elf_symbol_sptr
function_symbol_is_undefined(const string&);
elf_symbol_sptr
variable_symbol_is_undefined(const string&);
static symtab_ptr
load(Elf* elf_handle,
const ir::environment& env,
@@ -283,6 +307,14 @@ private:
/// Lookup map function entry address -> symbol
addr_symbol_map_type entry_addr_symbol_map_;
/// Set of undefined function symbol names
std::unordered_set<std::string> undefined_function_linkage_names_;
/// of undefined variable function symbol names
std::unordered_set<std::string> undefined_variable_linkage_names_;
bool cached_undefined_symbol_names_;
bool
load_(Elf* elf_handle,
const ir::environment& env,
@@ -304,6 +336,9 @@ private:
void
add_alternative_address_lookups(Elf* elf_handle);
void
collect_undefined_fns_and_vars_linkage_names();
};
/// Helper class to allow range-for loops on symtabs for C++11 and later code.
+475 -41
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
///@file
@@ -35,6 +35,7 @@
#include <libgen.h>
#include <libxml/parser.h>
#include <libxml/xmlversion.h>
#include <lzma.h>
#include <algorithm>
#include <cstdlib>
#include <cstring>
@@ -43,6 +44,7 @@
#include <iterator>
#include <memory>
#include <sstream>
#include <regex>
#include "abg-dwarf-reader.h"
#ifdef WITH_CTF
@@ -53,6 +55,7 @@
#endif
#include "abg-internal.h"
#include "abg-regex.h"
#include "abg-libxml-utils.h"
// <headers defining libabigail's API go under here>
ABG_BEGIN_EXPORT_DECLARATIONS
@@ -87,8 +90,7 @@ namespace tools_utils
void
initialize()
{
LIBXML_TEST_VERSION;
xmlInitParser();
xml::initialize();
}
/// Get the value of $libdir variable of the autotools build
@@ -416,9 +418,12 @@ is_regular_file(const string& path)
if (S_ISREG(st.st_mode))
return true;
string symlink_target_path;
if (maybe_get_symlink_target_file_path(path, symlink_target_path))
return is_regular_file(symlink_target_path);
if (S_ISLNK(st.st_mode))
{
string symlink_target_path;
if (maybe_get_symlink_target_file_path(path, symlink_target_path))
return is_regular_file(symlink_target_path);
}
return false;
}
@@ -456,7 +461,7 @@ dir_contains_ctf_archive(const string& directory,
/// that contains debug info.
bool
file_has_dwarf_debug_info(const string& elf_file_path,
const vector<char**>& debug_info_root_paths)
const vector<string>& debug_info_root_paths)
{
if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
return false;
@@ -492,7 +497,7 @@ file_has_dwarf_debug_info(const string& elf_file_path,
/// that contains debug info.
bool
file_has_ctf_debug_info(const string& elf_file_path,
const vector<char**>& debug_info_root_paths)
const vector<string>& debug_info_root_paths)
{
if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
return false;
@@ -516,7 +521,7 @@ file_has_ctf_debug_info(const string& elf_file_path,
// vmlinux.ctfa could be provided with --debug-info-dir
for (const auto& path : debug_info_root_paths)
if (find_file_under_dir(*path, "vmlinux.ctfa", vmlinux))
if (!path.empty() && find_file_under_dir(path, "vmlinux.ctfa", vmlinux))
return true;
return false;
@@ -536,7 +541,7 @@ file_has_ctf_debug_info(const string& elf_file_path,
/// that contains debug info.
bool
file_has_btf_debug_info(const string& elf_file_path,
const vector<char**>& debug_info_root_paths)
const vector<string>& debug_info_root_paths)
{
if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
return false;
@@ -1347,6 +1352,79 @@ trim_white_space(const string& str)
return result;
}
/// Remove white spaces from a string.
///
/// @param str the string to remove the white spaces from.
///
/// @return true iff any white space was removed from @p str.
bool
remove_white_spaces(string& str)
{
if (str.erase(std::remove_if(str.begin(), str.end(), isspace),
str.end()) == str.end())
return false;
return true;
}
/// Getter of a global instance of std::regex that matches numerical
/// litterals.
///
/// The regular expression is the following: "([0-9]+)([uUlL])+"
///
/// The purpose of this is to compile the regular expression only
/// once, the first time this function is invoked. Subsquent
/// invocations return the already compiled regular expression.
///
/// @return a reference to a global instance of std::regex
static std::regex&
get_litteral_regex()
{
static std::regex re("([0-9]+)([uUlL])+");
return re;
}
/// Normalize the numerical litteral in a string.
///
/// Basically, if a litteral is present as 10u or 100UL, change it
/// into 10 or 100.
///
/// @param str the string to normalize.
///
/// @return true iff @p str was normalized.
bool
normalize_litterals(string& str)
{
bool begin_pattern = false, middle_pattern = false, found_litteral = false;
for (string::iterator i = str.begin(); i < str.end(); ++i)
{
if (isdigit(*i))
begin_pattern = true;
else
{
if (begin_pattern
&& (*i == 'u' || *i == 'U' || *i == 'l' || *i == 'L'))
middle_pattern = true;
else
{
if (middle_pattern)
{
found_litteral = true;
break;
}
}
}
}
if (found_litteral)
{
std::regex& re = get_litteral_regex();
str = std::regex_replace(str, re, "$1");
return true;
}
return false;
}
/// Remove a string of pattern in front of a given string.
///
/// For instance, consider this string:
@@ -1552,12 +1630,43 @@ operator<<(ostream& output,
case FILE_TYPE_TAR:
repr = "GNU tar archive type";
break;
case FILE_TYPE_XZ:
repr = "XZ compressed file";
}
output << repr;
return output;
}
/// The kind of compression we want a de-compression std::streambuf
/// for.
///
/// This enum must be amended to add support for new compression
/// schemes, especially whenever a new enumerator is added to the enum
/// @ref file_type.
enum compression_kind
{
COMPRESSION_KIND_UNKNOWN,
/// The LZMA compression (used by the xz tool).
COMPRESSION_KIND_XZ
}; //end enum compression_kind
/// Test if one of the enumerators of @ref file_type designates a
/// compression scheme.
///
/// This helper function needs to be updated whenever a new
/// compression-related enumerator is added to @ref file_type.
///
/// @return the kind of compression designated by @p t.
static compression_kind
is_compressed_file_type(file_type t)
{
if (t == FILE_TYPE_XZ)
return COMPRESSION_KIND_XZ;
return COMPRESSION_KIND_UNKNOWN;
}
/// Guess the type of the content of an input stream.
///
/// @param in the input stream to guess the content type for.
@@ -1569,11 +1678,11 @@ guess_file_type(istream& in)
const unsigned BUF_LEN = 264;
const unsigned NB_BYTES_TO_READ = 263;
char buf[BUF_LEN];
unsigned char buf[BUF_LEN];
memset(buf, 0, BUF_LEN);
std::streampos initial_pos = in.tellg();
in.read(buf, NB_BYTES_TO_READ);
in.read(reinterpret_cast<char*>(buf), NB_BYTES_TO_READ);
in.seekg(initial_pos);
if (in.gcount() < 4 || in.bad())
@@ -1585,6 +1694,17 @@ guess_file_type(istream& in)
&& buf[3] == 'F')
return FILE_TYPE_ELF;
// XZ format. Described at
// https://tukaani.org/xz/xz-file-format.txt.
if (in.gcount() >= 6
&& buf[0] == 0xFD
&& buf[1] == '7'
&& buf[2] == 'z'
&& buf[3] == 'X'
&& buf[4] == 'Z'
&& buf[5] == 0)
return FILE_TYPE_XZ;
if (buf[0] == '!'
&& buf[1] == '<'
&& buf[2] == 'a'
@@ -1593,7 +1713,7 @@ guess_file_type(istream& in)
&& buf[5] == 'h'
&& buf[6] == '>')
{
if (strstr(buf, "debian-binary"))
if (strstr(reinterpret_cast<char*>(buf), "debian-binary"))
return FILE_TYPE_DEB;
else
return FILE_TYPE_AR;
@@ -1646,6 +1766,8 @@ guess_file_type(istream& in)
&& buf[11] == ' ')
return FILE_TYPE_XML_CORPUS;
// Detect RPM format. Documented at
// http://ftp.rpm.org/max-rpm/s1-rpm-file-format-rpm-file-format.html.
if ((unsigned char) buf[0] == 0xed
&& (unsigned char) buf[1] == 0xab
&& (unsigned char) buf[2] == 0xee
@@ -1669,13 +1791,53 @@ guess_file_type(istream& in)
return FILE_TYPE_UNKNOWN;
}
/// The factory of an std::streambuf aimed at decompressing data
/// coming from an input stream compressed with a particular
/// compression scheme.
///
/// This function must be amended to add support for new compression
/// schemes.
///
/// @param compressed_input the compressed input to create the
/// decompressor std::streambuf for.
///
/// @param compr the compression scheme kind.
///
/// @return a pointer to the std::streambuf to use for decompression.
/// If the compression scheme is not supported, the function returns
/// nil.
static shared_ptr<std::streambuf>
get_decompressed_streambuf(std::istream& compressed_input,
compression_kind compr)
{
shared_ptr<std::streambuf> result;
switch(compr)
{
case COMPRESSION_KIND_UNKNOWN:
ABG_ASSERT_NOT_REACHED;
break;
case COMPRESSION_KIND_XZ:
shared_ptr<std::streambuf> r(new xz_decompressor_type(compressed_input));
result = r;
break;
};
return result;
};// end struct compression_handler_type
/// Guess the type of the content of an file.
///
/// @param file_path the path to the file to consider.
///
/// @param look_through_compression if true, then decompress the file
/// and try to guess the type of the decompressed content. Otherwise,
/// just return that it's a compressed type.
///
/// @return the type of content guessed.
file_type
guess_file_type(const string& file_path)
guess_file_type(const string& file_path, bool look_through_compression)
{
if (is_dir(file_path))
return FILE_TYPE_DIR;
@@ -1697,9 +1859,68 @@ guess_file_type(const string& file_path)
|| string_ends_with(file_path, ".tz"))
return FILE_TYPE_TAR;
ifstream in(file_path.c_str(), ifstream::binary);
file_type r = guess_file_type(in);
in.close();
file_type r = FILE_TYPE_UNKNOWN;
compression_kind compr_kind = COMPRESSION_KIND_UNKNOWN;
shared_ptr<std::streambuf> decompressor_streambuf;
if (string_ends_with(file_path, ".lzma")
|| string_ends_with(file_path, ".lz")
|| string_ends_with(file_path, ".xz"))
{
r = FILE_TYPE_XZ;
compr_kind = COMPRESSION_KIND_XZ;
}
// else if there are other compression schemes supported, recognize
// their file suffix here!
if (is_compressed_file_type(r) && !look_through_compression)
return r;
do
{
shared_ptr<ifstream> input_fstream(new ifstream(file_path.c_str(),
ifstream::binary));
shared_ptr<istream> input_stream = input_fstream;
if (compr_kind != COMPRESSION_KIND_UNKNOWN)
decompressor_streambuf = get_decompressed_streambuf(*input_stream,
compr_kind);
if (decompressor_streambuf)
input_stream.reset(new istream(decompressor_streambuf.get()));
r = guess_file_type(*input_stream);
input_fstream->close();
if (!decompressor_streambuf)
{
// So we haven't attempted to decompress the input stream.
//
// Have we found out that it was compressed nonetheless?
compr_kind = is_compressed_file_type(r);
if (compr_kind)
{
if (!look_through_compression)
// The caller wants us to report that this file is
// compressed.
return r;
// We found out the input file is compressed, so we do
// have the means to decompress it. However, we haven't
// yet gotten the de-compressor; that might be because
// we detected the compression just by looking at the
// file name suffix. Let's go back to calling
// get_decompressed_streambuf again to get the
// decompressor.
;
}
else
// No the file is not compressed let's get out of here.
break;
}
} while (!decompressor_streambuf && compr_kind);
return r;
}
@@ -1862,7 +2083,7 @@ file_is_kernel_package(const string& file_path, file_type file_type)
bool
rpm_contains_file(const string& rpm_path, const string& file_name)
{
vector<string> query_output;
vector<string> query_output;
// We don't check the return value of this command because on some
// system, the command can issue errors but still emit a valid
// output. We'll rather rely on the fact that the command emits a
@@ -1953,6 +2174,31 @@ make_path_absolute(const char*p)
return result;
}
/// Return a copy of the path given in argument, turning it into an
/// absolute path by prefixing it with the concatenation of the result
/// of get_current_dir_name() and the '/' character.
///
///
/// @param p the path to turn into an absolute path.
///
/// @return The resulting absolute path.
string
make_path_absolute(const string& p)
{
string result;
if (!p.empty() && p[0] != '/')
{
shared_ptr<char> pwd(get_current_dir_name(),
malloced_char_star_deleter());
result = string(pwd.get()) + "/" + p;
}
else if (!p.empty())
result = p;
return result;
}
/// Return a copy of the path given in argument, turning it into an
/// absolute path by prefixing it with the concatenation of the result
/// of get_current_dir_name() and the '/' character.
@@ -2003,7 +2249,7 @@ handle_file_entry(const string& file_path,
{
if (!suppr)
{
suppr.reset(new type_suppression(get_private_types_suppr_spec_label(),
suppr.reset(new type_suppression(get_opaque_types_suppr_spec_label(),
/*type_name_regexp=*/"",
/*type_name=*/""));
@@ -2733,6 +2979,20 @@ is_kernel_module(const FTSENT *entry)
return false;
}
/// Test if a given file denoted by a FTSENT* is a regular file or a
/// symlink.
///
/// @param entry returned by the combo fts_open/fts_read.
///
/// @return true iff @p entry is for a regular file or a symlink.
static bool
is_file(const FTSENT *entry)
{
return (entry
&& (entry->fts_info == FTS_F
|| entry->fts_info == FTS_SL));
}
/// Find a vmlinux and its kernel modules in a given directory tree.
///
/// @param from the directory tree to start looking from.
@@ -2822,6 +3082,50 @@ find_vmlinux_path(const string& from,
return found_vmlinux;
}
/// Get all the sub-directories (which contain a regular file) of a
/// given directory.
///
/// @param root_dir the root directory to consider.
///
/// @param dirs the sub-directories of @p root_dir which contain a
/// file.
bool
get_file_path_dirs_under_dir(const string& root_dir, vector<string>& dirs)
{
char* paths[] = {const_cast<char*>(root_dir.c_str()), 0};
FTS *file_hierarchy = fts_open(paths,
FTS_PHYSICAL|FTS_NOCHDIR|FTS_XDEV, 0);
if (!file_hierarchy)
return false;
string r = root_dir;
if (!string_ends_with(r, "/"))
r += "/";
bool found_file = false;
FTSENT *entry;
while ((entry = fts_read(file_hierarchy)))
{
// Skip descendents of symbolic links.
if (entry->fts_info == FTS_SL || entry->fts_info == FTS_SLNONE)
{
fts_set(file_hierarchy, entry, FTS_SKIP);
continue;
}
if (is_file(entry))
found_file = true;
string path = entry->fts_path;
dir_name(path, path);
dirs.push_back(path);
}
fts_close(file_hierarchy);
return found_file;
}
/// Get the paths of the vmlinux and kernel module binaries under
/// given directory.
///
@@ -2855,7 +3159,7 @@ get_binary_paths_from_kernel_dist(const string& dist_root,
// under the 'debug_info_root_path' directory and its content is
// accessible from <debug_info_root_path>/usr/lib/debug directory.
string kernel_modules_root;
string kernel_modules_root = dist_root;
string debug_info_root;
if (dir_exists(dist_root + "/lib/modules"))
{
@@ -2989,7 +3293,7 @@ load_vmlinux_corpus(elf_based_reader_sptr rdr,
const string& vmlinux,
vector<string>& modules,
const string& root,
vector<char**>& di_roots,
vector<string>& di_roots,
vector<string>& suppr_paths,
vector<string>& kabi_wl_paths,
suppressions_type& supprs,
@@ -3000,6 +3304,13 @@ load_vmlinux_corpus(elf_based_reader_sptr rdr,
abigail::fe_iface::status status = abigail::fe_iface::STATUS_OK;
rdr->options().do_log = verbose;
if (verbose)
{
std::cerr << "Loading stable lists:'";
for (auto s : kabi_wl_paths)
std::cerr << s << ",";
std::cerr << "'...\n";
}
t.start();
load_generate_apply_suppressions(*rdr, suppr_paths,
kabi_wl_paths, supprs);
@@ -3025,7 +3336,7 @@ load_vmlinux_corpus(elf_based_reader_sptr rdr,
if (verbose)
std::cerr << vmlinux
<< " reading DONE:"
<< " reading DONE in:"
<< t << "\n";
if (group->is_empty())
@@ -3043,7 +3354,7 @@ load_vmlinux_corpus(elf_based_reader_sptr rdr,
<< *m << "' ("
<< cur_module_index
<< "/" << total_nb_modules
<< ") ... " << std::flush;
<< ") ...\n" << std::flush;
rdr->initialize(*m, di_roots,
/*read_all_types=*/false,
@@ -3058,10 +3369,18 @@ load_vmlinux_corpus(elf_based_reader_sptr rdr,
rdr->read_and_add_corpus_to_group(*group, status);
t.stop();
if (verbose)
std::cerr << "module '"
<< *m
<< "' reading DONE: "
<< t << "\n";
std::cerr << "Module reading DONE in: "
<< t << " for '" << *m
<< "' (" << cur_module_index << "/" << total_nb_modules << ")"
<< "'\n";
}
if (verbose)
{
std::cerr << "Total number of functions: "
<< group->get_functions().size() << "\n";
std::cerr << "Total number of variables: "
<< group->get_variables().size() << "\n";
}
}
@@ -3122,7 +3441,7 @@ build_corpus_group_from_kernel_dist_under(const string& root,
<< root
<< "' with vmlinux path: '"
<< vmlinux_path
<< "' ... " << std::flush;
<< "' ... \n" << std::flush;
timer t;
@@ -3132,23 +3451,21 @@ build_corpus_group_from_kernel_dist_under(const string& root,
t.stop();
if (verbose)
std::cerr << "DONE: " << t << "\n";
std::cerr << "Kernel tree binary paths analysis DONE in: " << t << "\n";
if (got_binary_paths)
{
shared_ptr<char> di_root =
make_path_absolute(debug_info_root.c_str());
char *di_root_ptr = di_root.get();
vector<char**> di_roots;
di_roots.push_back(&di_root_ptr);
string di_root =
make_path_absolute(debug_info_root);
vector<string> di_roots;
di_roots.push_back(di_root);
#ifdef WITH_CTF
shared_ptr<char> di_root_ctf;
string di_root_ctf;
if (requested_fe_kind & corpus::CTF_ORIGIN)
{
di_root_ctf = make_path_absolute(root.c_str());
char *di_root_ctf_ptr = di_root_ctf.get();
di_roots.push_back(&di_root_ctf_ptr);
di_root_ctf = make_path_absolute(root);
di_roots.push_back(di_root_ctf);
}
#endif
@@ -3206,7 +3523,7 @@ build_corpus_group_from_kernel_dist_under(const string& root,
/// designated by @p elf_file_path.
elf_based_reader_sptr
create_best_elf_based_reader(const string& elf_file_path,
const vector<char**>& debug_info_root_paths,
const vector<string>& debug_info_root_paths,
environment& env,
corpus::origin requested_fe_kind,
bool show_all_types,
@@ -3227,7 +3544,8 @@ create_best_elf_based_reader(const string& elf_file_path,
{
#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);
result = btf::create_reader(elf_file_path, debug_info_root_paths, env,
show_all_types, linux_kernel_mode);
#endif
}
else
@@ -3246,7 +3564,8 @@ create_best_elf_based_reader(const string& elf_file_path,
&& 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);
result = btf::create_reader(elf_file_path, debug_info_root_paths, env,
show_all_types, linux_kernel_mode);
#endif
}
@@ -3265,6 +3584,121 @@ create_best_elf_based_reader(const string& elf_file_path,
return result;
}
/// ---------------------------------------------------
/// <xz_decompressor definition>
///----------------------------------------------------
/// The private data of the @ref xz_decompressor_type class.
struct xz_decompressor_type::priv
{
std::istream& xz_istream;
lzma_stream lzma;
// A 100k bytes buffer for xz data coming from the xz'ed istream.
// That buffer is going to be fed into the lzma decoding machinery.
char inbuf[1024 * 100] = {};
// A 100k bytes buffer for decompressed data coming out of the lzma
// machinery
char outbuf[1024 * 100] = {};
priv(std::istream& i)
: xz_istream(i),
lzma(LZMA_STREAM_INIT)
{}
};// end xz_decompressor_type::priv
/// Constructor of the @ref xz_decompressor_type class.
///
/// @param xz_istream the input stream containing the xz-compressed
/// data to decompress.
xz_decompressor_type::xz_decompressor_type(std::istream& xz_istream)
: priv_(new priv(xz_istream))
{
// Initialize the native LZMA stream to decompress.
lzma_ret status = lzma_stream_decoder(&priv_->lzma,
UINT64_MAX,
LZMA_CONCATENATED);
ABG_ASSERT(status == LZMA_OK);
}
/// Destructor of the @ref xz_decompressor_type class.
xz_decompressor_type::~xz_decompressor_type()
{
lzma_end(&priv_->lzma);
}
/// The implementation of the virtual protected
/// std:streambuf::underflow method. This method is invoked by the
/// std::streambuf facility to re-fill its internals buffers with data
/// coming from the associated input stream and to update the gptr()
/// and egptr() pointers by using the std::streambuf::setg method.
///
/// This is where the decompression using the lzma library is
/// performed.
std::streambuf::int_type
xz_decompressor_type::underflow()
{
if (gptr() < egptr())
return *gptr();
// Let's read 'nr' bytes of xz data into inbuf
priv_->xz_istream.read(priv_->inbuf, sizeof(priv_->inbuf));
size_t nr = priv_->xz_istream.gcount();
if (nr != 0)
{
// So there is fresh compressed input to be decompressed. Let's
// prepare the lzma input stream machinery then.
priv_->lzma.avail_in = nr;
priv_->lzma.next_in = reinterpret_cast<uint8_t*>(priv_->inbuf);
}
if (priv_->lzma.avail_out || priv_->lzma.avail_in)
{
// There is still compressed data in the lzma context to
// decompress, so let's tell lzma where to put the decompressed
// data.
priv_->lzma.avail_out = sizeof(priv_->outbuf);
priv_->lzma.next_out = reinterpret_cast<uint8_t*>(priv_->outbuf);
}
// Let's now ask the lzma machinery to decompress the next_in buffer
// and put the result into the next_out buffer.
lzma_ret result = lzma_code(&priv_->lzma, LZMA_RUN);
if (result != LZMA_OK && result != LZMA_STREAM_END)
{
// TODO: list the possible error codes and tell them explicitely
// to the user, just like what is done in
// https://github.com/tukaani-project/xz/blob/master/doc/examples/02_decompress.c.
std::ostringstream o;
o << "LZMA decompression failed;"
<< " return code of lzma_code() is : "
<< result;
throw std::runtime_error(o.str());
}
// Let's get the number of bytes decompressed by the lzma
// machinery. I got this from the example in the xz code base at
// https://github.com/tukaani-project/xz/blob/master/doc/examples/02_decompress.c.
size_t nr_decompressed_bytes = sizeof(priv_->outbuf) - priv_->lzma.avail_out;
// Now set the relevant index pointers of this streambuf.
setg(priv_->outbuf, priv_->outbuf, priv_->outbuf + nr_decompressed_bytes);
if (nr_decompressed_bytes > 0)
return *gptr();
// If we reached this point, then it means we there is no more
// decompressed bytes in the decompressed stream. Tell the lzma
// machinery that we've reached the end of the data.
result = lzma_code(&priv_->lzma, LZMA_FINISH);
ABG_ASSERT(result == LZMA_OK || result == LZMA_STREAM_END);
return traits_type::eof();
}
/// ---------------------------------------------------
/// </xz_decompressor definition>
///----------------------------------------------------
}//end namespace tools_utils
using abigail::ir::function_decl;
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
/// @file
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
#include <stdexcept>
#include <fstream>
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
#include <stdexcept>
#include <fstream>
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
#include <stdexcept>
#include <fstream>
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
// Copyright (C) 2013-2025 Red Hat, Inc.
//
// Author: Dodji Seketeli
+539 -368
View File
File diff suppressed because it is too large Load Diff
+43
View File
@@ -0,0 +1,43 @@
/*
* xxHash - Extremely Fast Hash algorithm
* Copyright (C) 2012-2021 Yann Collet
*
* BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You can contact the author at:
* - xxHash homepage: https://www.xxhash.com
* - xxHash source repository: https://github.com/Cyan4973/xxHash
*/
/*
* xxhash.c instantiates functions defined in xxhash.h
*/
#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */
#define XXH_IMPLEMENTATION /* access definitions */
#include "xxhash.h"

Some files were not shown because too many files have changed in this diff Show More