mirror of
https://github.com/openharmony/third_party_libabigail.git
synced 2026-07-01 06:09:52 -04:00
update version to 2.8
Signed-off-by: lizhenlin <lizhenlin2@h-partners.com>
This commit is contained in:
@@ -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",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
+10
-3
@@ -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
|
||||
|
||||
@@ -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
@@ -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."
|
||||
|
||||
@@ -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>
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+335
-235
@@ -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
@@ -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
@@ -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
@@ -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),
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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
@@ -19,6 +19,7 @@ Tools manuals
|
||||
abipkgdiff
|
||||
kmidiff
|
||||
abidw
|
||||
abidb
|
||||
abicompat
|
||||
abilint
|
||||
fedabipkgdiff
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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,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
@@ -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__
|
||||
|
||||
@@ -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,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,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,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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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,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
File diff suppressed because it is too large
Load Diff
@@ -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,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
@@ -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
@@ -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,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,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&,
|
||||
|
||||
@@ -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,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,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,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,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,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,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,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
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+67
-41
@@ -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
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,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
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+3876
-1445
File diff suppressed because it is too large
Load Diff
+111
-130
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
Reference in New Issue
Block a user