mirror of
https://github.com/openharmony/third_party_libabigail.git
synced 2026-07-01 06:09:52 -04:00
@@ -1,3 +1,204 @@
|
||||
2.4
|
||||
===
|
||||
Dmitry V. Levin (1):
|
||||
elf-helpers: make sure config.h is included first
|
||||
|
||||
Dodji Seketeli (58):
|
||||
Update website for the 2.3 release
|
||||
release-text-template.txt: Modernize a little bit.
|
||||
dwarf-reader: Don't compute canonical type while propagating one
|
||||
Bug 29693 - clang-libs from f37 fails self test
|
||||
Bug 30466 - harfbuzz fails self-check on f38
|
||||
Bug 30467 - enlightenment fails self check on f38
|
||||
configure.ac: Bump to 2.4 version
|
||||
Bug 30503 - Fail to compare non-anonymous struct vs named struct data members
|
||||
Bug 30461 - insight fails self-compare
|
||||
fedabipkgdiff: Don't choke Koji servers with self-signed SSL certs
|
||||
fedabipkgdiff: Fix previous commit
|
||||
Make fe_iface::initialize independent from the kind of interface
|
||||
corpus,tools-utils: Support loading a corpus, its deps & other binaries
|
||||
abidw: Add --{follow,list}-dependencies & --add-binaries support
|
||||
abidiff: Add --{follow,list}-dependencies & add-binaries{1,2} support
|
||||
reader: Fix a long standing Thinko
|
||||
ir: Remove an unnecessary comparison
|
||||
reader: fix indentation
|
||||
tools-utils: Fix indentation
|
||||
dwarf-reader,ir: Make logging a property of the middle end
|
||||
dwarf-reader: Fix some logging
|
||||
abipkgdiff: Initialize libxml2 to use it in a multi-thread context
|
||||
tools-utils: Avoid endless loop
|
||||
{dwarf,elf}reader: Don't consider no symbol table as an error
|
||||
abipkgdiff: Avoid comparing binaries that are outside of the package
|
||||
ir: Add missing ABG_RETURN in the comparison engine
|
||||
ir: Add fn types to type lookup maps
|
||||
ir: Fix forgetting canonicalizing some function types
|
||||
ir: Avoid forgetting potential seemingly duplicated member functions
|
||||
ir: Really avoid canonicalizing decl-only classes
|
||||
ir: Use non qualified typedef name for type canonicalization
|
||||
ir: Fix qualification as non-confirmed propagated canonical types
|
||||
dwarf-reader: Do not re-use typedefs in a scope
|
||||
elf-reader, ir: Fix compilation on GCC 4.8.5
|
||||
configure,test-diff-pkg.cc: Handle symlinks presence in dist tarball
|
||||
libabigail-concepts.rst: Sort the properties of the directives
|
||||
libabigail-concepts.rst: Remove trailing white spaces
|
||||
test-abidiff-exit: Do not use debuginfo dir when its empty
|
||||
ir: Fix output of 'debug(enum-type)'
|
||||
comparison: Always apply filters on the diff graph
|
||||
abg-comparison[-priv]: Better detection of incompatible unreachable type changes
|
||||
doc/manuals/libabigail-concepts.rst: Fix typo
|
||||
suppression: Fix indentation
|
||||
suppression: Fix a typo in apidoc
|
||||
Bug 30959 - Crash on malformed fn call expression
|
||||
ini: Support '[' and ']' in arguments of function call expressions
|
||||
init: Fix thinko in apidoc
|
||||
ir: Remove redundant virtual member functions
|
||||
Bug 30971 - Wrong interpretation of "has_data_member_inserted_at"
|
||||
default-reporter,reporter-priv: Do not report names of anonymous enums
|
||||
ir,comparison,corpus: Better support anonymous enums comparison
|
||||
ir,comparison: Represent changed anonymous enums
|
||||
comparison: Represent changed unreachable anonymous unions, structs & enums
|
||||
Support suppressing data member insertion before a flexible array member
|
||||
suppression: Make the "end" data member offset selector be named boundary
|
||||
ir: Fix compilation error with GCC 4.8.5
|
||||
gen-changelog.py: Don't escaping '/' with '\' in regexp
|
||||
gen-changelog.py: Fix a long standing typo
|
||||
|
||||
Giuliano Procida (1):
|
||||
operator!= fixes for C++-20
|
||||
|
||||
John Moon (1):
|
||||
suppression: Add "changed_enumerators_regexp" property
|
||||
|
||||
Matthias Maennich (2):
|
||||
symtab reader: use C++11 `using` syntax instead of typedefs
|
||||
symtab reader: fix symtab iterator to support C++20
|
||||
|
||||
Yaakov Selkowitz (1):
|
||||
Fix fedabipkgdiff configure check for Python 3.12
|
||||
|
||||
|
||||
2.3
|
||||
===
|
||||
Aleksei Vetrov (1):
|
||||
symtab: fix getting CRC in relocatable modules
|
||||
|
||||
Ben Woodard (1):
|
||||
Have fedabipkgdiff sleep while waiting for abipkgdiff
|
||||
|
||||
Dodji Seketeli (92):
|
||||
ir: Improve get_debug_representation
|
||||
ir: Add a debug_comp_stack debugging function
|
||||
Bug 29857 - Don't pop comparison operands that haven't been pushed
|
||||
Bug 29857 - dwarf-reader: Resolve decl-only unions
|
||||
Bug 29857 - Better detect comparison cycles in type graph
|
||||
ir: Cache more aggregate type comparison results
|
||||
NEWS: Update for 2.2 release
|
||||
ChangeLog: Update for 2.2 release
|
||||
configure: Bump version number to 2.3
|
||||
Update website documentation for 2.2
|
||||
Bug 29901 - abidiff hangs when comparing libgs.so.10 with itself
|
||||
Bug 29934 - Handle buggy data members with empty names
|
||||
dwarf-reader: Bug 29932 - Handle function DIE as type as needed
|
||||
elf-reader: Don't free CTF resources too early
|
||||
ir: misc cleanups
|
||||
ir: Bug 29934 - Fix propagated canonical type confirmation
|
||||
ir: Add sanity checking to canonical type propagation confirmation
|
||||
Update copyright year for 2023
|
||||
Don't use the "infinite" keyword for arrays of unknown size
|
||||
dwarf-reader: Bug 29811 - Support updating of variable type
|
||||
Bug 29811 - Better categorize harmless unknown array size changes
|
||||
fix comparing array subrange DIEs
|
||||
configure: Enable the CTF front-end by default
|
||||
Add support for BTF
|
||||
Update the copyright notice for the BTF reader
|
||||
btf-reader: Use abigail::ir::canonicalize_types to canonicalize types
|
||||
Better detect suitable libctf version
|
||||
Update CTF's ctf_dict_t detection
|
||||
fe-iface: Add missing virtual destructor
|
||||
dwarf-reader: Remove unused code
|
||||
corpus: Handle empty symbol table cases
|
||||
{dwarf,elf_based}-reader,writer: Avoid duplicating corpora in corpus_group
|
||||
default-reporter: Fix source location in functions change report
|
||||
PR30048 - wrong pretty representation of qualified pointers
|
||||
configure: Bump the CURRENT library number
|
||||
ir: Add missing virtual methods overloads
|
||||
ctf-reader: Fix GCC 13 warnings
|
||||
abipkgdiff: Emit better logs in verbose mode
|
||||
abipkgdiff: Emit error when no vmlinux is found in debug package
|
||||
ini: Fix parsing list property values
|
||||
suppr: Support has_data_member and has_data_member_regexp properties
|
||||
suppression: Factorize out is_data_member_offset_in_range
|
||||
suppression: Support the has_size_change property for suppress_type
|
||||
suppression: Support offset_of_{first,last}_data_member_regexp offset selectors
|
||||
comparison, suppression: Support [allow_type] directive
|
||||
Misc white space fixes
|
||||
abidiff: Add extensive logging
|
||||
tools-utils: Support kernel stablelist
|
||||
comp-filter: Don't re-visit node while applying filters to diff nodes
|
||||
comparison: Add a mode to not apply filters on interface sub-graphs
|
||||
comparison: When marking leaf nodes don't do unnecessary impact analysis
|
||||
comp-filter: Speed up harmless/harmful categorization
|
||||
tools-utils: Improve logging in build_corpus_group_from_kernel_dist_under
|
||||
ir: Fix cycle detection for union types
|
||||
Bug 29977 - dwarf-reader: Fix canonical DIE propagation canceling
|
||||
dwarf-reader,abidiff: Fix compilation with --enable-debug-type-canonicalization
|
||||
Bug 29912 - Better support an ELF symbol alias that designates several functions
|
||||
Bug 29911 - fedabipkgdiff forgets to provide some debuginfo RPMs to abipkgdiff
|
||||
Bug 29692 - Support binaries with empty symbol table
|
||||
abipkgdiff: Fix a typo
|
||||
test-symtab: Update after support for empty symtabs
|
||||
Bug 29690 - Out of range exception in add_or_update_class_type
|
||||
Bug 29686 - Fix testing the presence of anonymous data member in a struct
|
||||
Bug 29345 - abipkgdiff is confused by symlinked binaries in RPMs
|
||||
Bug 29340 - Add support for Ada range types
|
||||
Fix redundancy filtering of range types
|
||||
Bug rhbz#2182807 -- abipkgdiff crashes on missing debuginfo package
|
||||
dwarf-reader: Support Ada subranges having upper_bound < lower_bound
|
||||
abipkgdiff: Don't use user-specific filesystem info in error msg
|
||||
reader: Make reader::get_scope_for_node handle subranges at array scope.
|
||||
dwarf-reader: Support DW_OP_GNU_variable_value
|
||||
dwarf-reader: Fix typo in comment
|
||||
dwarf-reader: Support indirectly referenced subrange_type DIEs
|
||||
fedabipkgdiff: Add timing data in debug logs
|
||||
fedabipkgdiff: Remove busy loop when forking abipkgdiff
|
||||
Bug 29339 - elf-helpers: Don't crash on unexpected ELF file
|
||||
abi{dw,diff}: Better error messages when alternate debuginfo not found
|
||||
abidiff,reader: Fix compilation with --debug-self-comparison
|
||||
ir: Add new environment::get_type_id_from_type
|
||||
ir: Recognize "void* as being equal to all other pointers in C
|
||||
tests/update-test-output.py: Adapt to some broken test output
|
||||
Improve self-comparison debug mode
|
||||
ir: Improve debugging type_base::get_canonical_type_for
|
||||
writer: Annotate pointer representation
|
||||
comparison: Fix index error when interpreting scope comparison
|
||||
ir: fix canonical type propagation canceling error
|
||||
reader: Recognize variadic parameter type from abixml
|
||||
Bug 30309 - Support absolute path to alt debug info file in DWARF
|
||||
Fix the test of the patch for Bug 30309
|
||||
test-abidiff-exit: Fix the command line passed to abidiff
|
||||
ini: Do not crash on incorrect property value
|
||||
test-ini: Fix a typo
|
||||
|
||||
Giuliano Procida (1):
|
||||
DWARF reader: avoid C++20 operator!= overload ambiguity
|
||||
|
||||
Guillermo E. Martinez (4):
|
||||
ctf-front-end: Add test for alias symbols
|
||||
ctf-reader: Fix missing initializer for member in test suite
|
||||
abipkgdiff: Fix kernel package detection when comparing kABIs
|
||||
tools-utils: Fix looking for vmlinux binary in debuginfo package
|
||||
|
||||
Mark Wielaard (1):
|
||||
doc: Fix some typos and add some missing references
|
||||
|
||||
Petr Pavlu (2):
|
||||
Fix de-initialization of elf::reader::priv
|
||||
abidiff: Fix handling of linux-kernel-mode
|
||||
|
||||
Xiaole He (1):
|
||||
elf-reader: reclaim fd and mem before break
|
||||
|
||||
|
||||
2.2
|
||||
===
|
||||
Aleksei Vetrov (1):
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
__attribute__((visibility("hidden"))) */
|
||||
#define HAS_GCC_VISIBILITY_ATTRIBUTE 1
|
||||
|
||||
/* struct ctf_dict_t is present */
|
||||
#define HAVE_CTF_DICT_T 1
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
@@ -68,8 +71,8 @@
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
/* Define to 1 if you have the <minix/config.h> header file. */
|
||||
/* #undef HAVE_MINIX_CONFIG_H */
|
||||
|
||||
/* Defined to 1 if elf.h has R_AARCH64_ABS64 macro defined */
|
||||
#define HAVE_R_AARCH64_ABS64_MACRO 1
|
||||
@@ -80,6 +83,9 @@
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#define HAVE_STDIO_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
@@ -98,6 +104,9 @@
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* 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
|
||||
|
||||
@@ -117,7 +126,7 @@
|
||||
#define PACKAGE_NAME "libabigail"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "libabigail 2.2"
|
||||
#define PACKAGE_STRING "libabigail 2.4"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "libabigail"
|
||||
@@ -126,42 +135,131 @@
|
||||
#define PACKAGE_URL "http://sourceware.org/libabigail"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "2.2"
|
||||
#define PACKAGE_VERSION "2.4"
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
/* Define to 1 if all of the C90 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. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# define _ALL_SOURCE 1
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE 1
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# define _POSIX_PTHREAD_SEMANTICS 1
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# define _TANDEM_SOURCE 1
|
||||
/* Enable general extensions on macOS. */
|
||||
#ifndef _DARWIN_C_SOURCE
|
||||
# define _DARWIN_C_SOURCE 1
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# define __EXTENSIONS__ 1
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE 1
|
||||
#endif
|
||||
/* Enable X/Open compliant socket functions that do not require linking
|
||||
with -lxnet on HP-UX 11.11. */
|
||||
#ifndef _HPUX_ALT_XOPEN_SOCKET_API
|
||||
# define _HPUX_ALT_XOPEN_SOCKET_API 1
|
||||
#endif
|
||||
/* Identify the host operating system as Minix.
|
||||
This macro does not affect the system headers' behavior.
|
||||
A future release of Autoconf may stop defining this macro. */
|
||||
#ifndef _MINIX
|
||||
/* # undef _MINIX */
|
||||
#endif
|
||||
/* Enable general extensions on NetBSD.
|
||||
Enable NetBSD compatibility extensions on Minix. */
|
||||
#ifndef _NETBSD_SOURCE
|
||||
# define _NETBSD_SOURCE 1
|
||||
#endif
|
||||
/* Enable OpenBSD compatibility extensions on NetBSD.
|
||||
Oddly enough, this does nothing on OpenBSD. */
|
||||
#ifndef _OPENBSD_SOURCE
|
||||
# define _OPENBSD_SOURCE 1
|
||||
#endif
|
||||
/* Define to 1 if needed for POSIX-compatible behavior. */
|
||||
#ifndef _POSIX_SOURCE
|
||||
/* # undef _POSIX_SOURCE */
|
||||
#endif
|
||||
/* Define to 2 if needed for POSIX-compatible behavior. */
|
||||
#ifndef _POSIX_1_SOURCE
|
||||
/* # undef _POSIX_1_SOURCE */
|
||||
#endif
|
||||
/* Enable POSIX-compatible threading on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# define _POSIX_PTHREAD_SEMANTICS 1
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */
|
||||
#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
|
||||
# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */
|
||||
#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
|
||||
# define __STDC_WANT_IEC_60559_BFP_EXT__ 1
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */
|
||||
#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
|
||||
# define __STDC_WANT_IEC_60559_DFP_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. */
|
||||
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */
|
||||
#ifndef __STDC_WANT_LIB_EXT2__
|
||||
# define __STDC_WANT_LIB_EXT2__ 1
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC 24747:2009. */
|
||||
#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
|
||||
# define __STDC_WANT_MATH_SPEC_FUNCS__ 1
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# define _TANDEM_SOURCE 1
|
||||
#endif
|
||||
/* Enable X/Open extensions. Define to 500 only if necessary
|
||||
to make mbstate_t available. */
|
||||
#ifndef _XOPEN_SOURCE
|
||||
/* # undef _XOPEN_SOURCE */
|
||||
#endif
|
||||
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "2.2"
|
||||
#define VERSION "2.4"
|
||||
|
||||
/* Defined if user enabled BTF usage */
|
||||
#define WITH_BTF 1
|
||||
|
||||
/* struct btf_enum64 is present */
|
||||
#define WITH_BTF_ENUM64 1
|
||||
|
||||
/* The BTF_KIND_DECL_TAG enumerator is present */
|
||||
/* #undef WITH_BTF_KIND_DECL_TAG */
|
||||
|
||||
/* The BTF_KIND_TYPE_TAG enumerator is present */
|
||||
/* #undef WITH_BTF_KIND_TYPE_TAG */
|
||||
|
||||
/* The function btf__get_nr_types is present */
|
||||
/* #undef WITH_BTF__GET_NR_TYPES */
|
||||
|
||||
/* The function btf__type_cnt is present */
|
||||
#define WITH_BTF__TYPE_CNT 1
|
||||
|
||||
/* Defined if user enables and system has the libctf library */
|
||||
/* #undef WITH_CTF */
|
||||
#define WITH_CTF 1
|
||||
|
||||
/* 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 */
|
||||
|
||||
@@ -173,31 +271,19 @@
|
||||
#define WITH_RPM 1
|
||||
|
||||
/* has rpm/zstd support */
|
||||
/* #undef WITH_RPM_ZSTD */
|
||||
#define WITH_RPM_ZSTD 1
|
||||
|
||||
/* compile support of abilint --show-type-use */
|
||||
/* #undef WITH_SHOW_TYPE_USE_IN_ABILINT */
|
||||
|
||||
/* symbolic links are kept in the distribution tarball */
|
||||
#define WITH_SYMLINKS_KEPT_IN_DIST 1
|
||||
|
||||
/* compile the GNU tar archive support in abipkgdiff */
|
||||
#define WITH_TAR 1
|
||||
|
||||
/* Enable large inode numbers on Mac OS X 10.5. */
|
||||
#ifndef _DARWIN_USE_64_BIT_INODE
|
||||
# define _DARWIN_USE_64_BIT_INODE 1
|
||||
#endif
|
||||
|
||||
/* 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. */
|
||||
/* #undef _LARGE_FILES */
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
/* #undef _MINIX */
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */
|
||||
/* #undef _POSIX_1_SOURCE */
|
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
/* #undef _POSIX_SOURCE */
|
||||
|
||||
+288
@@ -0,0 +1,288 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Defined if the compiler supports the attribution visibility syntax
|
||||
__attribute__((visibility("hidden"))) */
|
||||
#undef HAS_GCC_VISIBILITY_ATTRIBUTE
|
||||
|
||||
/* struct ctf_dict_t is present */
|
||||
#undef HAVE_CTF_DICT_T
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if dwarf.h has the DW_FORM_line_strp enumerator */
|
||||
#undef HAVE_DW_FORM_line_strp
|
||||
|
||||
/* Define to 1 if dwarf.h has the DW_FORM_strx enumerators */
|
||||
#undef HAVE_DW_FORM_strx
|
||||
|
||||
/* Define to 1 if dwarf.h has the DW_FORM_strx1 enumerator */
|
||||
#undef HAVE_DW_FORM_strx1
|
||||
|
||||
/* Define to 1 if dwarf.h has the DW_FORM_strx2 enumerator */
|
||||
#undef HAVE_DW_FORM_strx2
|
||||
|
||||
/* Define to 1 if dwarf.h has the DW_FORM_strx3 enumerator */
|
||||
#undef HAVE_DW_FORM_strx3
|
||||
|
||||
/* 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_C11 enumerator */
|
||||
#undef HAVE_DW_LANG_C11_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
|
||||
|
||||
/* Define to 1 if dwarf.h has the DW_LANG_C_plus_plus_11 enumerator */
|
||||
#undef HAVE_DW_LANG_C_plus_plus_11_enumerator
|
||||
|
||||
/* 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_D enumerator */
|
||||
#undef HAVE_DW_LANG_D_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_Mips_Assembler enumerator */
|
||||
#undef HAVE_DW_LANG_Mips_Assembler_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_Rust enumerator */
|
||||
#undef HAVE_DW_LANG_Rust_enumerator
|
||||
|
||||
/* Define to 1 if dwarf.h has the DW_LANG_UPC enumerator */
|
||||
#undef HAVE_DW_LANG_UPC_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_TILEGX macro defined */
|
||||
#undef HAVE_EM_TILEGX_MACRO
|
||||
|
||||
/* Defined to 1 if elf.h has EM_TILEPR0 macro defined */
|
||||
#undef HAVE_EM_TILEPRO_MACRO
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <minix/config.h> header file. */
|
||||
#undef HAVE_MINIX_CONFIG_H
|
||||
|
||||
/* Defined to 1 if elf.h has R_AARCH64_ABS64 macro defined */
|
||||
#undef HAVE_R_AARCH64_ABS64_MACRO
|
||||
|
||||
/* Defined to 1 if elf.h has R_AARCH64_PREL32 macro defined */
|
||||
#undef HAVE_R_AARCH64_PREL32_MACRO
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#undef HAVE_STDIO_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* 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
|
||||
|
||||
/* Define to 1 if assertions should be disabled. */
|
||||
#undef NDEBUG
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* 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
|
||||
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. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on macOS. */
|
||||
#ifndef _DARWIN_C_SOURCE
|
||||
# undef _DARWIN_C_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
/* Enable X/Open compliant socket functions that do not require linking
|
||||
with -lxnet on HP-UX 11.11. */
|
||||
#ifndef _HPUX_ALT_XOPEN_SOCKET_API
|
||||
# undef _HPUX_ALT_XOPEN_SOCKET_API
|
||||
#endif
|
||||
/* Identify the host operating system as Minix.
|
||||
This macro does not affect the system headers' behavior.
|
||||
A future release of Autoconf may stop defining this macro. */
|
||||
#ifndef _MINIX
|
||||
# undef _MINIX
|
||||
#endif
|
||||
/* Enable general extensions on NetBSD.
|
||||
Enable NetBSD compatibility extensions on Minix. */
|
||||
#ifndef _NETBSD_SOURCE
|
||||
# undef _NETBSD_SOURCE
|
||||
#endif
|
||||
/* Enable OpenBSD compatibility extensions on NetBSD.
|
||||
Oddly enough, this does nothing on OpenBSD. */
|
||||
#ifndef _OPENBSD_SOURCE
|
||||
# undef _OPENBSD_SOURCE
|
||||
#endif
|
||||
/* Define to 1 if needed for POSIX-compatible behavior. */
|
||||
#ifndef _POSIX_SOURCE
|
||||
# undef _POSIX_SOURCE
|
||||
#endif
|
||||
/* Define to 2 if needed for POSIX-compatible behavior. */
|
||||
#ifndef _POSIX_1_SOURCE
|
||||
# undef _POSIX_1_SOURCE
|
||||
#endif
|
||||
/* Enable POSIX-compatible threading on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */
|
||||
#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */
|
||||
#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_BFP_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */
|
||||
#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_DFP_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. */
|
||||
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */
|
||||
#ifndef __STDC_WANT_LIB_EXT2__
|
||||
# undef __STDC_WANT_LIB_EXT2__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC 24747:2009. */
|
||||
#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
|
||||
# undef __STDC_WANT_MATH_SPEC_FUNCS__
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable X/Open extensions. Define to 500 only if necessary
|
||||
to make mbstate_t available. */
|
||||
#ifndef _XOPEN_SOURCE
|
||||
# undef _XOPEN_SOURCE
|
||||
#endif
|
||||
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Defined if user enabled BTF usage */
|
||||
#undef WITH_BTF
|
||||
|
||||
/* struct btf_enum64 is present */
|
||||
#undef WITH_BTF_ENUM64
|
||||
|
||||
/* The BTF_KIND_DECL_TAG enumerator is present */
|
||||
#undef WITH_BTF_KIND_DECL_TAG
|
||||
|
||||
/* The BTF_KIND_TYPE_TAG enumerator is present */
|
||||
#undef WITH_BTF_KIND_TYPE_TAG
|
||||
|
||||
/* The function btf__get_nr_types is present */
|
||||
#undef WITH_BTF__GET_NR_TYPES
|
||||
|
||||
/* The function btf__type_cnt is present */
|
||||
#undef WITH_BTF__TYPE_CNT
|
||||
|
||||
/* Defined if user enables and system has the libctf library */
|
||||
#undef WITH_CTF
|
||||
|
||||
/* 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
|
||||
|
||||
/* compile support of debugging type canonicalization while using abidw
|
||||
--debug-tc */
|
||||
#undef WITH_DEBUG_TYPE_CANONICALIZATION
|
||||
|
||||
/* compile the rpm package support in abipkgdiff */
|
||||
#undef WITH_RPM
|
||||
|
||||
/* has rpm/zstd support */
|
||||
#undef WITH_RPM_ZSTD
|
||||
|
||||
/* compile support of abilint --show-type-use */
|
||||
#undef WITH_SHOW_TYPE_USE_IN_ABILINT
|
||||
|
||||
/* symbolic links are kept in the distribution tarball */
|
||||
#undef WITH_SYMLINKS_KEPT_IN_DIST
|
||||
|
||||
/* compile the GNU tar archive support in abipkgdiff */
|
||||
#undef WITH_TAR
|
||||
|
||||
/* 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. */
|
||||
#undef _LARGE_FILES
|
||||
+158
-11
@@ -3,7 +3,7 @@
|
||||
dnl Libabigail version number is handled here with the major and minor
|
||||
dnl version numbers.
|
||||
m4_define([version_major], [2])
|
||||
m4_define([version_minor], [2])
|
||||
m4_define([version_minor], [4])
|
||||
|
||||
dnl Below are the numbers to handle libabigail.so's versionning
|
||||
dnl following the libtool's versionning scheme to handle shared
|
||||
@@ -25,7 +25,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], [1])
|
||||
m4_define([libabigail_so_current], [3])
|
||||
m4_define([libabigail_so_revision], [0])
|
||||
m4_define([libabigail_so_age], [0])
|
||||
|
||||
@@ -62,11 +62,29 @@ AM_MAINTAINER_MODE([enable])
|
||||
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
dnl By default, the tar command used by 'make dist and make distcheck'
|
||||
dnl is "tar --format=ustar -chf" where the "-h" option actually
|
||||
dnl follows symbolic links. So it copies the targets of the symlinks
|
||||
dnl that are present in the tarball. Unfortunately, there are
|
||||
dnl tests that need to keep the symlinks intact in the tarball.
|
||||
dnl
|
||||
dnl So let's define a tar command without the -h option.
|
||||
|
||||
am__tar='tar --format=ustar -cf - "$$tardir"'
|
||||
|
||||
VERSION_MAJOR=version_major
|
||||
VERSION_MINOR=version_minor
|
||||
VERSION_REVISION=0
|
||||
dnl The major version number of the abixml version should be changed
|
||||
dnl only if a new version of libabigail cannot read an old version of
|
||||
dnl abixml. This should be very rare and should be avoided as much as
|
||||
dnl possible.
|
||||
ABIXML_VERSION_MAJOR=2
|
||||
ABIXML_VERSION_MINOR=1
|
||||
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
|
||||
LIBABIGAIL_SO_CURRENT=libabigail_so_current
|
||||
LIBABIGAIL_SO_REVISION=libabigail_so_revision
|
||||
LIBABIGAIL_SO_AGE=libabigail_so_age
|
||||
@@ -116,6 +134,12 @@ 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],
|
||||
['enable abilint --show-type-use'(default is no)]),
|
||||
@@ -193,8 +217,14 @@ AC_ARG_ENABLE(ctf,
|
||||
AS_HELP_STRING([--enable-ctf=yes|no],
|
||||
[disable support of ctf files)]),
|
||||
ENABLE_CTF=$enableval,
|
||||
ENABLE_CTF=no)
|
||||
ENABLE_CTF=auto)
|
||||
|
||||
dnl check if user has enabled BTF code
|
||||
AC_ARG_ENABLE(btf,
|
||||
AS_HELP_STRING([--enable-btf=yes|no],
|
||||
[disable support of btf files)]),
|
||||
ENABLE_BTF=$enableval,
|
||||
ENABLE_BTF=auto)
|
||||
dnl *************************************************
|
||||
dnl check for dependencies
|
||||
dnl *************************************************
|
||||
@@ -311,21 +341,117 @@ AC_SUBST([ELF_LIBS])
|
||||
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
|
||||
dnl found on the system
|
||||
CTF_LIBS=
|
||||
if test x$ENABLE_CTF = xyes; then
|
||||
if test x$ENABLE_CTF != xno; then
|
||||
CTF_HEADER=no
|
||||
AC_CHECK_HEADER([ctf.h],
|
||||
[CTF_HEADER=yes],
|
||||
[AC_MSG_NOTICE([could not find ctf.h, going to disable CTF support])])
|
||||
LIBCTF=
|
||||
AC_CHECK_LIB(ctf, ctf_open, [LIBCTF=yes], [LIBCTF=no])
|
||||
if test x$CTF_HEADER = xyes; then
|
||||
AC_CHECK_LIB(ctf, ctf_open, [LIBCTF=yes], [LIBCTF=no])
|
||||
fi
|
||||
|
||||
if test x$LIBCTF = xyes; then
|
||||
AC_MSG_NOTICE([activating CTF code])
|
||||
dnl Test if struct struct ctf_dict_t is present.
|
||||
AC_LANG(C++)
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#include <ctf-api.h>
|
||||
ctf_dict_t* c;]])],
|
||||
[HAVE_CTF_DICT_T=yes],
|
||||
[HAVE_CTF_DICT_T=no])
|
||||
|
||||
if test x$HAVE_CTF_DICT_T = xyes; then
|
||||
AC_DEFINE([HAVE_CTF_DICT_T], 1, [struct ctf_dict_t is present])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x$HAVE_CTF_DICT_T = xno; then
|
||||
AC_MSG_NOTICE([Some needed data structures are missing from ctf-api.h. Disabling CTF support.])
|
||||
LIBCTF=no
|
||||
fi
|
||||
|
||||
if test x$LIBCTF = xyes; then
|
||||
AC_MSG_NOTICE([CTF support enabled])
|
||||
AC_DEFINE([WITH_CTF], 1,
|
||||
[Defined if user enables and system has the libctf library])
|
||||
CTF_LIBS=-lctf
|
||||
ENABLE_CTF=yes
|
||||
else
|
||||
AC_MSG_NOTICE([CTF enabled but no libctf found])
|
||||
AC_MSG_NOTICE([no suitable libctf found, CTF support was disabled])
|
||||
ENABLE_CTF=no
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl configure BTF usage
|
||||
BPF_LIBS=
|
||||
if test x$ENABLE_BTF != xno; then
|
||||
AC_CHECK_HEADER([bpf/btf.h],
|
||||
[ENABLE_BTF=yes],
|
||||
[AC_MSG_NOTICE([could not find bpf/btf.h])])
|
||||
if test x$ENABLE_BTF = xyes; then
|
||||
AC_MSG_NOTICE([enable BTF support])
|
||||
ENABLE_BTF=yes
|
||||
AC_DEFINE([WITH_BTF], 1,
|
||||
[Defined if user enabled BTF usage])
|
||||
BPF_LIBS=-lbpf
|
||||
else
|
||||
AC_MSG_NOTICE([BTF support was disabled])
|
||||
ENABLE_BTF=no
|
||||
fi
|
||||
|
||||
dnl Test if various functions and structs are present.
|
||||
|
||||
if test x$ENABLE_BTF = xyes; then
|
||||
dnl Test if struct btf_enum64 is present.
|
||||
AC_CHECK_TYPE([struct btf_enum64],
|
||||
[HAVE_BTF_ENUM64=yes],
|
||||
[HAVE_BTF_ENUM64=no],
|
||||
[#include <bpf/btf.h>])
|
||||
|
||||
if test x$HAVE_BTF_ENUM64 = xyes; then
|
||||
AC_DEFINE([WITH_BTF_ENUM64], 1, [struct btf_enum64 is present])
|
||||
fi
|
||||
|
||||
dnl Test if btf__get_nr_types is present
|
||||
AC_CHECK_DECL([btf__get_nr_types],
|
||||
[HAVE_BTF__GET_NR_TYPES=yes],
|
||||
[HAVE_BTF__GET_NR_TYPES=no],
|
||||
[#include <bpf/btf.h>])
|
||||
|
||||
if test x$HAVE_BTF__GET_NR_TYPES = xyes; then
|
||||
AC_DEFINE(WITH_BTF__GET_NR_TYPES, 1, [The function btf__get_nr_types is present])
|
||||
fi
|
||||
|
||||
dnl Test if btf__type_cnt is present
|
||||
AC_CHECK_DECL([btf__type_cnt],
|
||||
[HAVE_BTF__TYPE_CNT=yes],
|
||||
[HAVE_BTF__TYPE_CNT=no],
|
||||
[#include <bpf/btf.h>])
|
||||
if test x$HAVE_BTF__TYPE_CNT = xyes; then
|
||||
AC_DEFINE(WITH_BTF__TYPE_CNT, 1, [The function btf__type_cnt is present])
|
||||
fi
|
||||
|
||||
dnl Test if BTF_KIND_TYPE_TAG exists
|
||||
AC_CHECK_DECL([int kind = BTF_KIND_TYPE_TAG],
|
||||
[HAVE_BTF_KIND_TYPE_TAG=yes],
|
||||
[HAVE_BTF_KIND_TYPE_TAG=no],
|
||||
[#include <bpf/btf.h>])
|
||||
if test x$HAVE_BTF_KIND_TYPE_TAG = xyes; then
|
||||
AC_DEFINE([WITH_BTF_KIND_TYPE_TAG], 1,
|
||||
[The BTF_KIND_TYPE_TAG enumerator is present])
|
||||
fi
|
||||
|
||||
dnl Test if BTF_KIND_DECL_TAG exists
|
||||
AC_CHECK_DECL([int kind = BTF_KIND_DECL_TAG],
|
||||
[HAVE_BTF_KIND_DECL_TAG=yes],
|
||||
[HAVE_BTF_KIND_DECL_TAG=no],
|
||||
[#include <bpf/btf.h>])
|
||||
if test x$HAVE_BTF_KIND_DECL_TAG = xyes; then
|
||||
AC_DEFINE([WITH_BTF_KIND_DECL_TAG], 1,
|
||||
[The BTF_KIND_DECL_TAG enumerator is present])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl Check for dependency: libxml
|
||||
LIBXML2_VERSION=2.6.22
|
||||
PKG_CHECK_MODULES(XML, libxml-2.0 >= $LIBXML2_VERSION)
|
||||
@@ -402,6 +528,13 @@ fi
|
||||
|
||||
AM_CONDITIONAL(ENABLE_RPM, test x$ENABLE_RPM = xyes)
|
||||
|
||||
dnl There is a test that needs symlinks support in the distribution tarball. If symlinks are
|
||||
dnl removed from the tarball, then the test should be disabled.
|
||||
m4_define([symlink_file], [tests/data/test-diff-pkg/symlink-dir-test1/dir1/symlinks/foo.o])
|
||||
if test -L "$srcdir"/symlink_file; then
|
||||
AC_DEFINE([WITH_SYMLINKS_KEPT_IN_DIST], 1, [symbolic links are kept in the distribution tarball])
|
||||
fi
|
||||
|
||||
dnl enable the debugging of self comparison when doing abidw --debug-abidiff <binary>
|
||||
if test x$ENABLE_DEBUG_SELF_COMPARISON = xyes; then
|
||||
AC_DEFINE([WITH_DEBUG_SELF_COMPARISON], 1, [compile support of debugging abidw --abidiff])
|
||||
@@ -434,6 +567,15 @@ 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)
|
||||
@@ -614,13 +756,15 @@ if test x$CHECK_DEPS_FOR_FEDABIPKGDIFF = xyes; then
|
||||
# urllib.parse. Oh well.
|
||||
if test x$PYTHON = xpython3; then
|
||||
URLPARSE_MODULE=urllib.parse
|
||||
IMPORT_MODULE=importlib.machinery
|
||||
else
|
||||
URLPARSE_MODULE=urlparse
|
||||
IMPORT_MODULE=imp
|
||||
fi
|
||||
|
||||
REQUIRED_PYTHON_MODULES_FOR_FEDABIPKGDIFF="\
|
||||
argparse logging os re subprocess sys $URLPARSE_MODULE \
|
||||
xdg koji mock rpm imp tempfile mimetypes shutil six"
|
||||
xdg koji mock rpm $IMPORT_MODULE tempfile mimetypes shutil six"
|
||||
|
||||
AX_CHECK_PYTHON_MODULES([$REQUIRED_PYTHON_MODULES_FOR_FEDABIPKGDIFF],
|
||||
[$PYTHON],
|
||||
@@ -719,7 +863,7 @@ AX_VALGRIND_CHECK
|
||||
|
||||
dnl Set the list of libraries libabigail depends on
|
||||
|
||||
DEPS_LIBS="$XML_LIBS $ELF_LIBS $DW_LIBS $CTF_LIBS"
|
||||
DEPS_LIBS="$XML_LIBS $ELF_LIBS $DW_LIBS $CTF_LIBS $BPF_LIBS"
|
||||
AC_SUBST(DEPS_LIBS)
|
||||
|
||||
if test x$ABIGAIL_DEVEL != x; then
|
||||
@@ -760,6 +904,7 @@ fi
|
||||
dnl Set a few Automake conditionals
|
||||
|
||||
AM_CONDITIONAL([CTF_READER],[test "x$ENABLE_CTF" = "xyes"])
|
||||
AM_CONDITIONAL([BTF_READER],[test "x$ENABLE_BTF" = "xyes"])
|
||||
|
||||
dnl Set the level of C++ standard we use.
|
||||
CXXFLAGS="$CXXFLAGS -std=$CXX_STANDARD"
|
||||
@@ -1063,12 +1208,14 @@ AC_MSG_NOTICE([
|
||||
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 python 3 : ${ENABLE_PYTHON3}
|
||||
Enable CTF front-end : ${ENABLE_CTF}
|
||||
Enable BTF front-end : ${ENABLE_BTF}
|
||||
Enable running tests under Valgrind : ${enable_valgrind}
|
||||
Enable build with -fsanitize=address : ${ENABLE_ASAN}
|
||||
Enable build with -fsanitize=memory : ${ENABLE_MSAN}
|
||||
|
||||
+112
-2
@@ -16,8 +16,9 @@ For a comprehensive ABI change report between two input shared
|
||||
libraries that includes changes about function and variable sub-types,
|
||||
``abidiff`` uses by default, debug information in `DWARF`_ format, if
|
||||
present, otherwise it compares interfaces using debug information in
|
||||
`CTF`_ format, if present, finally, if neither is found, it uses only
|
||||
`ELF`_ symbols to report which of them were added or removed.
|
||||
`CTF`_ or `BTF`_ formats, if present. Finally, if no debug info in
|
||||
these formats is found, it only considers `ELF`_ symbols and report
|
||||
about their addition or removal.
|
||||
|
||||
.. include:: tools-use-libabigail.txt
|
||||
|
||||
@@ -176,6 +177,72 @@ Options
|
||||
library that the tool has to consider. The tool will thus filter
|
||||
out ABI changes on types that are not defined in public headers.
|
||||
|
||||
* ``--add-binaries1`` <*bin1,bin2,bin3,..*>
|
||||
|
||||
For each of the comma-separated binaries given in argument to this
|
||||
option, if the binary is found in the directory specified by the
|
||||
``--added-binaries-dir1`` option, then ``abidiff`` loads the ABI
|
||||
corpus of the binary and adds it to a set of corpora (called an
|
||||
ABI Corpus Group) that includes the first argument of ``abidiff``.
|
||||
|
||||
That ABI corpus group is then compared against the second corpus
|
||||
group given in argument to ``abidiff``.
|
||||
|
||||
* ``--add-binaries2`` <*bin1,bin2,bin3,..*>
|
||||
|
||||
For each of the comma-separated binaries given in argument to this
|
||||
option, if the binary is found in the directory specified by the
|
||||
``--added-binaries-dir2`` option, then ``abidiff`` loads the ABI
|
||||
corpus of the binary and adds it to a set of corpora(called an ABI
|
||||
Corpus Group) that includes the second argument of ``abidiff``.
|
||||
|
||||
That ABI corpus group is then compared against the first corpus
|
||||
group given in argument to ``abidiff``.
|
||||
|
||||
* ``--follow-dependencies | --fdeps``
|
||||
|
||||
For each dependency of the first argument of ``abidiff``, if it's
|
||||
found in the directory specified by the ``--added-binaries-dir1``
|
||||
option, then construct an ABI corpus out of the dependency, add it
|
||||
to a set of corpora (called an ABI Corpus Group) that includes the
|
||||
first argument of ``abidiff``.
|
||||
|
||||
Similarly, for each dependency of the second argument of
|
||||
``abidiff``, if it's found in the directory specified by the
|
||||
``--added-binaries-dir2`` option, then construct an ABI corpus out
|
||||
of the dependency, add it to an ABI corpus group that includes the
|
||||
second argument of ``abidiff``.
|
||||
|
||||
These two ABI corpus groups are then compared against each other.
|
||||
|
||||
Said otherwise, this makes ``abidiff`` compare the set of its
|
||||
first input and its dependencies against the set of its second
|
||||
input and its dependencies.
|
||||
|
||||
* ``list-dependencies | --ldeps``
|
||||
|
||||
This option lists all the dependencies of the input arguments of
|
||||
``abidiff`` that are found in the directories specified by the
|
||||
options ``--added-binaries-dir1`` and ``--added-binaries-dir2``
|
||||
|
||||
* ``--added-binaries-dir1 | --abd1`` <added-binaries-directory-1>
|
||||
|
||||
This option is to be used in conjunction with the
|
||||
``--add-binaries1``, ``--follow-dependencies`` and
|
||||
``--list-dependencies`` options. Binaries referred to by these
|
||||
options, if found in the directory `added-binaries-directory-1`,
|
||||
are loaded as ABI corpus and are added to the first ABI corpus group
|
||||
that is to be used in the comparison.
|
||||
|
||||
* ``--added-binaries-dir2 | --abd2`` <added-binaries-directory-2>
|
||||
|
||||
This option is to be used in conjunction with the
|
||||
``--add-binaries2``, ``--follow-dependencies`` and
|
||||
``--list-dependencies`` options. Binaries referred to by these
|
||||
options, if found in the directory `added-binaries-directory-2`,
|
||||
are loaded as ABI corpus and are added to the second ABI corpus
|
||||
group to be used in the comparison.
|
||||
|
||||
* ``--no-linux-kernel-mode``
|
||||
|
||||
Without this option, if abidiff detects that the binaries it is
|
||||
@@ -600,11 +667,28 @@ Options
|
||||
|
||||
This option disables those optimizations.
|
||||
|
||||
* ``--no-change-categorization | -x``
|
||||
|
||||
This option disables the categorization of changes into harmless
|
||||
and harmful changes. Note that this categorization is a
|
||||
pre-requisite for the filtering of changes so this option disables
|
||||
that filtering. The goal of this option is to speed-up the
|
||||
execution of the program for cases where the graph of changes is
|
||||
huge and where the user is just interested in looking at, for
|
||||
instance, leaf node changes without caring about their possible
|
||||
impact on interfaces. In that case, this option would be used
|
||||
along with the ``--leaf-changes-only`` one.
|
||||
|
||||
* ``--ctf``
|
||||
|
||||
When comparing binaries, extract ABI information from `CTF`_ debug
|
||||
information, if present.
|
||||
|
||||
* ``--btf``
|
||||
|
||||
When comparing binaries, extract ABI information from `BTF`_ debug
|
||||
information, if present.
|
||||
|
||||
* ``--stats``
|
||||
|
||||
Emit statistics about various internal things.
|
||||
@@ -827,9 +911,35 @@ Usage examples
|
||||
|
||||
$
|
||||
|
||||
4. Comparing two sets of binaries that are passed on the command line: ::
|
||||
|
||||
$ abidiff --add-binaries1=file2-v1 \
|
||||
--add-binaries2=file2-v2,file2-v1 \
|
||||
--added-binaries-dir1 dir1 \
|
||||
--added-binaries-dir2 dir2 \
|
||||
file1-v1 file1-v2
|
||||
|
||||
Note that the files ``file2-v1``, and ``file2-v2`` are to be
|
||||
found in ``dir1`` and ``dir2`` or in the current directory.
|
||||
|
||||
|
||||
5. Compare two libraries and their dependencies: ::
|
||||
|
||||
$ abidiff --follow-dependencies \
|
||||
--added-binaries-dir1 /some/where \
|
||||
--added-binaries-dir2 /some/where/else \
|
||||
foo bar
|
||||
|
||||
This compares the set of binaries comprised by ``foo`` and its
|
||||
dependencies against the set of binaries comprised by ``bar`` and
|
||||
its dependencies.
|
||||
|
||||
|
||||
.. _ELF: http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
|
||||
.. _DWARF: http://www.dwarfstd.org
|
||||
.. _CTF: https://raw.githubusercontent.com/wiki/oracle/binutils-gdb/files/ctf-spec.pdf
|
||||
.. _BTF: https://docs.kernel.org/bpf/btf.html
|
||||
.. _ODR: https://en.wikipedia.org/wiki/One_Definition_Rule
|
||||
.. _One Definition Rule: https://en.wikipedia.org/wiki/One_Definition_Rule
|
||||
.. _DWZ: https://sourceware.org/dwz
|
||||
.. _Linux Kernel: https://kernel.org/
|
||||
|
||||
+76
-7
@@ -21,14 +21,14 @@ functions and variables, along with a complete representation of their
|
||||
types.
|
||||
|
||||
To generate either ABI or KMI representation, by default ``abidw``
|
||||
uses debug information in `DWARF`_ format, if present, otherwise it
|
||||
looks for debug information in `CTF`_ format, if present, finally, if
|
||||
neither is found, it uses only `ELF`_ symbols to report which of them
|
||||
were added or removed.
|
||||
uses debug information in the `DWARF`_ format, if present, otherwise
|
||||
it looks for debug information in `CTF`_ or `BTF`_ formats, if present.
|
||||
Finally, if no debug info in these formats is found, it only considers
|
||||
`ELF`_ symbols and report about their addition or removal.
|
||||
|
||||
.. include:: tools-use-libabigail.txt
|
||||
|
||||
.. _abidiff_invocation_label:
|
||||
.. _abidw_invocation_label:
|
||||
|
||||
Invocation
|
||||
==========
|
||||
@@ -44,14 +44,49 @@ Options
|
||||
|
||||
Display a short help about the command and exit.
|
||||
|
||||
* `--version | -v`
|
||||
* ``--version | -v``
|
||||
|
||||
Display the version of the program and exit.
|
||||
|
||||
* `--abixml-version`
|
||||
* ``--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
|
||||
option, if the binary is found in the directory specified by the
|
||||
`--added-binaries-dir` option, then load the ABI corpus of the
|
||||
binary and add it to a set of ABI corpora (called a ABI Corpus
|
||||
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*>
|
||||
|
||||
This option is to be used in conjunction with the
|
||||
``--add-binaries``, the ``--follow-dependencies`` or the
|
||||
``--list-dependencies`` option. Binaries listed as arguments of
|
||||
the ``--add-binaries`` option or being dependencies of the input
|
||||
binary in the case of the ``--follow-dependencies`` option and
|
||||
found in the directory <*dir-path*> are going to be loaded as ABI
|
||||
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
|
||||
@@ -368,6 +403,39 @@ Options
|
||||
Emit verbose logs about the progress of miscellaneous internal
|
||||
things.
|
||||
|
||||
Usage examples
|
||||
==============
|
||||
|
||||
1. Emitting an ``ABIXML`` representation of a binary: ::
|
||||
|
||||
$ abidw binary > binary.abi
|
||||
|
||||
|
||||
2. Emitting an ``ABIXML`` representation of a set of binaries
|
||||
specified on the command line: ::
|
||||
|
||||
$ abidw --added-binaries=bin1,bin2,bin3 \
|
||||
--added-binaries-dir /some/where \
|
||||
binary > binaries.abi
|
||||
|
||||
Note that the binaries bin1, bin2 and bin3 are to be found in the
|
||||
directory ``/some/where``. A representation of the ABI of the
|
||||
set of binaries ``binary, bin1, bin2`` and ``bin3`` called an
|
||||
``ABI corpus group`` is serialized in the file binaries.abi.
|
||||
|
||||
3. Emitting an ``ABIXML`` representation of a binary and its
|
||||
dependencies: ::
|
||||
|
||||
$ abidw --follow-dependencies \
|
||||
--added-binaries-dir /some/where \
|
||||
binary > binary.abi
|
||||
|
||||
Note that only the dependencies that are found in the directory
|
||||
``/some/where`` are analysed. Their ABIs, along with the ABI the
|
||||
binary named ``binary`` are represented as an ABI corpus group
|
||||
and serialized in the file ``binary.abi``, in the ABIXML format.
|
||||
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
@@ -389,6 +457,7 @@ standard `here
|
||||
.. _GNU: http://www.gnu.org
|
||||
.. _Linux Kernel: https://kernel.org/
|
||||
.. _CTF: https://raw.githubusercontent.com/wiki/oracle/binutils-gdb/files/ctf-spec.pdf
|
||||
.. _BTF: https://docs.kernel.org/bpf/btf.html
|
||||
.. _ODR: https://en.wikipedia.org/wiki/One_Definition_Rule
|
||||
.. _One Definition Rule: https://en.wikipedia.org/wiki/One_Definition_Rule
|
||||
.. _DWZ: https://sourceware.org/dwz
|
||||
|
||||
@@ -13,17 +13,17 @@ binaries.
|
||||
For a comprehensive ABI change report that includes changes about
|
||||
function and variable sub-types, the two input packages must be
|
||||
accompanied with their debug information packages that contain debug
|
||||
information either in `DWARF`_ or in `CTF`_ formats. Please note
|
||||
however that some packages contain binaries that embed the debug
|
||||
information either in `DWARF`_, `CTF`_ or in `BTF`_ formats. Please
|
||||
note however that some packages contain binaries that embed the debug
|
||||
information directly in a section of said binaries. In those cases,
|
||||
obviously, no separate debug information package is needed as the tool
|
||||
will find the debug information inside the binaries.
|
||||
|
||||
By default, ``abipkgdiff`` uses debug information in `DWARF`_ format,
|
||||
if present, otherwise it compares binaries interfaces using debug
|
||||
information in `CTF`_ format, if present, finally, if neither is
|
||||
found, it uses only `ELF`_ symbols to report which of them were added
|
||||
or removed.
|
||||
information in `CTF`_ or in `BTF`_ formats, if present. Finally, if no
|
||||
debug info in these formats is found, it only considers `ELF`_ symbols
|
||||
and report about their addition or removal.
|
||||
|
||||
.. include:: tools-use-libabigail.txt
|
||||
|
||||
@@ -554,6 +554,11 @@ Options
|
||||
This is used to compare packages with `CTF`_ debug information,
|
||||
if present.
|
||||
|
||||
* ``--btf``
|
||||
|
||||
This is used to compare packages with `BTF`_ debug information,
|
||||
if present.
|
||||
|
||||
.. _abipkgdiff_return_value_label:
|
||||
|
||||
Return value
|
||||
@@ -573,7 +578,9 @@ In the later case, the value of the exit code is the same as for the
|
||||
.. _tar: https://en.wikipedia.org/wiki/Tar_%28computing%29
|
||||
.. _DWARF: http://www.dwarfstd.org
|
||||
.. _CTF: https://raw.githubusercontent.com/wiki/oracle/binutils-gdb/files/ctf-spec.pdf
|
||||
.. _BTF: https://docs.kernel.org/bpf/btf.html
|
||||
.. _Development Package: https://fedoraproject.org/wiki/Packaging:Guidelines?rd=Packaging/Guidelines#Devel_Packages
|
||||
.. _ODR: https://en.wikipedia.org/wiki/One_Definition_Rule
|
||||
.. _One Definition Rule: https://en.wikipedia.org/wiki/One_Definition_Rule
|
||||
.. _DWZ: https://sourceware.org/dwz
|
||||
.. _Linux Kernel: https://kernel.org/
|
||||
|
||||
+24
-6
@@ -74,10 +74,11 @@ functions and variables) between the Kernel and its modules. In
|
||||
practice, though, some users might want to compare a subset of the
|
||||
those interfaces.
|
||||
|
||||
By default, ``kmidiff`` uses debug information in `DWARF`_ format,
|
||||
if present, otherwise it compares interfaces using debug information
|
||||
in `CTF`_ format, if present, finally, if neither is found, it uses
|
||||
only `ELF`_ symbols to report which were added or removed.
|
||||
By default, ``kmidiff`` uses debug information in the `DWARF`_ debug
|
||||
info format, if present, otherwise it compares interfaces using `CTF`_
|
||||
or `BTF`_ debug info formats, if present. Finally, if no debug info
|
||||
in these formats is found, it only considers `ELF`_ symbols and report
|
||||
about their addition or removal.
|
||||
|
||||
Users can then define a "white list" of the interfaces to compare.
|
||||
Such a white list is a just a file in the "INI" format that looks
|
||||
@@ -177,10 +178,26 @@ Options
|
||||
the :ref:`default suppression specification files
|
||||
<abidiff_default_supprs_label>` are loaded .
|
||||
|
||||
* ``--no-change-categorization | -x``
|
||||
|
||||
This option disables the categorization of changes into harmless
|
||||
and harmful changes. Note that this categorization is a
|
||||
pre-requisite for the filtering of changes so this option disables
|
||||
that filtering. The goal of this option is to speed-up the
|
||||
execution of the program for cases where the graph of changes is
|
||||
huge and where the user is just interested in looking at, for
|
||||
instance, leaf node changes without caring about their possible
|
||||
impact on interfaces.
|
||||
|
||||
* ``--ctf``
|
||||
|
||||
Extract ABI information from `CTF`_ debug information, if present in
|
||||
the Kernel and Modules.
|
||||
Extract ABI information from `CTF`_ debug information, if present,
|
||||
in the Kernel and Modules.
|
||||
|
||||
* ``--btf``
|
||||
|
||||
Extract ABI information from `BTF`_ debug information, if present,
|
||||
in the Kernel and Modules.
|
||||
|
||||
* ``--impacted-interfaces | -i``
|
||||
|
||||
@@ -249,3 +266,4 @@ Options
|
||||
.. _Linux Kernel: https://kernel.org
|
||||
.. _DWARF: http://www.dwarfstd.org
|
||||
.. _CTF: https://raw.githubusercontent.com/wiki/oracle/binutils-gdb/files/ctf-spec.pdf
|
||||
.. _BTF: https://docs.kernel.org/bpf/btf.html
|
||||
|
||||
+547
-383
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
####################
|
||||
#################################
|
||||
Overview of the Abigail framework
|
||||
####################
|
||||
#################################
|
||||
|
||||
**ABIGAIL** stands for the Application Binary Interface Generic
|
||||
Analysis and Instrumentation Library.
|
||||
|
||||
+3
-3
@@ -104,7 +104,7 @@ def output_commits():
|
||||
hash = lin[16:].strip()
|
||||
try:
|
||||
rel = release_refs[hash]
|
||||
print("=== release %d.%d.%d ===\n" % (int(rel[0]), int(rel[1]), int(rel[2])))
|
||||
|
||||
except:
|
||||
pass
|
||||
buf = []
|
||||
@@ -121,7 +121,7 @@ def output_commits():
|
||||
|
||||
def get_rel_tags():
|
||||
# Populate the release_refs dict with the tags for previous releases
|
||||
reltagre = re.compile("^([a-z0-9]{40}) refs\/tags\/GNET-([0-9]+)[-_.]([0-9]+)[-_.]([0-9]+)")
|
||||
reltagre = re.compile("^([a-z0-9]{40}) refs/tags/libabigail-([0-9]+)[-_.]([0-9]+)[-_.]([0-9]+)")
|
||||
|
||||
cmd = ['git', 'show-ref', '--tags', '--dereference']
|
||||
p = subprocess.Popen(args=cmd, shell=False,
|
||||
@@ -134,7 +134,7 @@ def get_rel_tags():
|
||||
release_refs[sha] = (maj, min, nano)
|
||||
|
||||
def find_start_tag():
|
||||
starttagre = re.compile("^([a-z0-9]{40}) refs\/tags\/CHANGELOG_START")
|
||||
starttagre = re.compile("^([a-z0-9]{40}) refs/tags/CHANGELOG_START")
|
||||
cmd = ['git', 'show-ref', '--tags']
|
||||
p = subprocess.Popen(args=cmd, shell=False,
|
||||
stdout=subprocess.PIPE,
|
||||
|
||||
@@ -34,4 +34,8 @@ if CTF_READER
|
||||
pkginclude_HEADERS += abg-ctf-reader.h
|
||||
endif
|
||||
|
||||
if BTF_READER
|
||||
pkginclude_HEADERS += abg-btf-reader.h
|
||||
endif
|
||||
|
||||
EXTRA_DIST = abg-version.h.in
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2022-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
/// @file
|
||||
///
|
||||
/// This file contains the declarations of the front-end to analyze the
|
||||
/// BTF information contained in an ELF file.
|
||||
|
||||
#ifndef __ABG_BTF_READER_H__
|
||||
#define __ABG_BTF_READER_H__
|
||||
|
||||
#include "abg-elf-based-reader.h"
|
||||
|
||||
namespace abigail
|
||||
{
|
||||
|
||||
namespace btf
|
||||
{
|
||||
|
||||
elf_based_reader_sptr
|
||||
create_reader(const std::string& elf_path,
|
||||
const vector<char**>& debug_info_root_paths,
|
||||
environment& env,
|
||||
bool load_all_types = false,
|
||||
bool linux_kernel_mode = false);
|
||||
|
||||
}//end namespace btf
|
||||
}//end namespace abigail
|
||||
|
||||
#endif //__ABG_BTF_READER_H__
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -91,6 +91,13 @@ has_anonymous_data_member_change(const diff_sptr &d);
|
||||
bool
|
||||
has_data_member_replaced_by_anon_dm(const diff* diff);
|
||||
|
||||
bool
|
||||
is_var_1_dim_unknown_size_array_change(const diff*);
|
||||
|
||||
bool
|
||||
is_var_1_dim_unknown_size_array_change(const var_decl_sptr& var1,
|
||||
const var_decl_sptr& var2);
|
||||
|
||||
struct filter_base;
|
||||
/// Convenience typedef for a shared pointer to filter_base
|
||||
typedef shared_ptr<filter_base> filter_base_sptr;
|
||||
|
||||
+140
-21
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "abg-corpus.h"
|
||||
#include "abg-diff-utils.h"
|
||||
#include "abg-reporter.h"
|
||||
#include "abg-suppression.h"
|
||||
|
||||
namespace abigail
|
||||
{
|
||||
@@ -46,14 +47,6 @@ using diff_utils::insertion;
|
||||
using diff_utils::deletion;
|
||||
using diff_utils::edit_script;
|
||||
|
||||
class diff;
|
||||
|
||||
/// Convenience typedef for a shared_ptr for the @ref diff class
|
||||
typedef shared_ptr<diff> diff_sptr;
|
||||
|
||||
/// Convenience typedef for a weak_ptr for the @ref diff class
|
||||
typedef weak_ptr<diff> diff_wptr;
|
||||
|
||||
/// Hasher for @ref diff_sptr.
|
||||
struct diff_sptr_hasher
|
||||
{
|
||||
@@ -261,14 +254,6 @@ typedef unordered_map<string, elf_symbol_sptr> string_elf_symbol_map;
|
||||
/// value is a @ref var_diff_sptr.
|
||||
typedef unordered_map<string, var_diff_sptr> string_var_diff_ptr_map;
|
||||
|
||||
class diff_context;
|
||||
|
||||
/// Convenience typedef for a shared pointer of @ref diff_context.
|
||||
typedef shared_ptr<diff_context> diff_context_sptr;
|
||||
|
||||
/// Convenience typedef for a weak pointer of @ref diff_context.
|
||||
typedef weak_ptr<diff_context> diff_context_wptr;
|
||||
|
||||
class diff_node_visitor;
|
||||
|
||||
class diff_traversable_base;
|
||||
@@ -438,6 +423,25 @@ enum diff_category
|
||||
/// variable didn't change.
|
||||
BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY = 1 << 21,
|
||||
|
||||
/// 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,
|
||||
|
||||
/// 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,
|
||||
|
||||
/// 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,
|
||||
|
||||
/// A special enumerator that is the logical 'or' all the
|
||||
/// enumerators above.
|
||||
///
|
||||
@@ -466,6 +470,9 @@ enum diff_category
|
||||
| VAR_TYPE_CV_CHANGE_CATEGORY
|
||||
| VOID_PTR_TO_PTR_CHANGE_CATEGORY
|
||||
| BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY
|
||||
| HAS_ALLOWED_CHANGE_CATEGORY
|
||||
| HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
|
||||
| HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY
|
||||
}; // enum diff_category
|
||||
|
||||
diff_category
|
||||
@@ -541,6 +548,12 @@ public:
|
||||
string_diff_ptr_map&
|
||||
get_typedef_diff_map();
|
||||
|
||||
const string_diff_ptr_map&
|
||||
get_subrange_diff_map() const;
|
||||
|
||||
string_diff_ptr_map&
|
||||
get_subrange_diff_map();
|
||||
|
||||
const string_diff_ptr_map&
|
||||
get_array_diff_map() const;
|
||||
|
||||
@@ -642,6 +655,12 @@ public:
|
||||
|
||||
~diff_context();
|
||||
|
||||
bool
|
||||
do_log() const;
|
||||
|
||||
void
|
||||
do_log(bool);
|
||||
|
||||
void
|
||||
set_corpus_diff(const corpus_diff_sptr&);
|
||||
|
||||
@@ -730,15 +749,30 @@ public:
|
||||
void
|
||||
maybe_apply_filters(corpus_diff_sptr diff);
|
||||
|
||||
suppr::suppressions_type&
|
||||
const suppr::suppressions_type&
|
||||
suppressions() const;
|
||||
|
||||
suppr::suppressions_type&
|
||||
suppressions();
|
||||
|
||||
const suppr::suppressions_type&
|
||||
negated_suppressions() const;
|
||||
|
||||
const suppr::suppressions_type&
|
||||
direct_suppressions() const;
|
||||
|
||||
void
|
||||
add_suppression(const suppr::suppression_sptr suppr);
|
||||
|
||||
void
|
||||
add_suppressions(const suppr::suppressions_type& supprs);
|
||||
|
||||
bool
|
||||
perform_change_categorization() const;
|
||||
|
||||
void
|
||||
perform_change_categorization(bool);
|
||||
|
||||
void
|
||||
show_leaf_changes_only(bool f);
|
||||
|
||||
@@ -950,6 +984,12 @@ protected:
|
||||
type_or_decl_base_sptr second_subject,
|
||||
diff_context_sptr ctxt);
|
||||
|
||||
bool
|
||||
do_log() const;
|
||||
|
||||
void
|
||||
do_log(bool);
|
||||
|
||||
void
|
||||
begin_traversing();
|
||||
|
||||
@@ -1037,6 +1077,9 @@ public:
|
||||
bool
|
||||
is_filtered_out_wrt_non_inherited_categories() const;
|
||||
|
||||
bool
|
||||
is_filtered_out_without_looking_at_allowed_changes() const;
|
||||
|
||||
bool
|
||||
is_suppressed() const;
|
||||
|
||||
@@ -1049,6 +1092,15 @@ public:
|
||||
bool
|
||||
has_local_changes_to_be_reported() const;
|
||||
|
||||
bool
|
||||
is_allowed_by_specific_negated_suppression() const;
|
||||
|
||||
bool
|
||||
has_descendant_allowed_by_specific_negated_suppression() const;
|
||||
|
||||
bool
|
||||
has_parent_allowed_by_specific_negated_suppression() const;
|
||||
|
||||
virtual const string&
|
||||
get_pretty_representation() const;
|
||||
|
||||
@@ -1363,6 +1415,61 @@ compute_diff(reference_type_def_sptr first,
|
||||
reference_type_def_sptr second,
|
||||
diff_context_sptr ctxt);
|
||||
|
||||
|
||||
class subrange_diff;
|
||||
|
||||
/// A convenience typedef for a shared pointer to subrange_diff type.
|
||||
typedef shared_ptr<subrange_diff> subrange_diff_sptr;
|
||||
|
||||
/// The abstraction of the diff between two subrange types.
|
||||
class subrange_diff : public type_diff_base
|
||||
{
|
||||
struct priv;
|
||||
std::unique_ptr<priv> priv_;
|
||||
|
||||
protected:
|
||||
subrange_diff(const array_type_def::subrange_sptr& first,
|
||||
const array_type_def::subrange_sptr& second,
|
||||
const diff_sptr& underlying_type_diff,
|
||||
const diff_context_sptr ctxt = diff_context_sptr());
|
||||
|
||||
public:
|
||||
const array_type_def::subrange_sptr
|
||||
first_subrange() const;
|
||||
|
||||
const array_type_def::subrange_sptr
|
||||
second_subrange() const;
|
||||
|
||||
const diff_sptr
|
||||
underlying_type_diff() const;
|
||||
|
||||
virtual const string&
|
||||
get_pretty_representation() const;
|
||||
|
||||
virtual bool
|
||||
has_changes() const;
|
||||
|
||||
virtual enum change_kind
|
||||
has_local_changes() const;
|
||||
|
||||
virtual void
|
||||
report(ostream&, const string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
chain_into_hierarchy();
|
||||
|
||||
friend subrange_diff_sptr
|
||||
compute_diff(array_type_def::subrange_sptr first,
|
||||
array_type_def::subrange_sptr second,
|
||||
diff_context_sptr ctxt);
|
||||
}; // end subrange_diff
|
||||
|
||||
subrange_diff_sptr
|
||||
compute_diff(array_type_def::subrange_sptr first,
|
||||
array_type_def::subrange_sptr second,
|
||||
diff_context_sptr ctxt);
|
||||
|
||||
|
||||
class array_diff;
|
||||
|
||||
/// Convenience typedef for a shared pointer on a @ref
|
||||
@@ -1604,6 +1711,12 @@ public:
|
||||
const string_decl_base_sptr_map&
|
||||
deleted_data_members() const;
|
||||
|
||||
const unsigned_var_diff_sptr_map&
|
||||
changed_data_members() const;
|
||||
|
||||
const var_diff_sptrs_type&
|
||||
sorted_changed_data_members() const;
|
||||
|
||||
const edit_script&
|
||||
member_fns_changes() const;
|
||||
|
||||
@@ -1619,9 +1732,6 @@ public:
|
||||
const string_member_function_sptr_map&
|
||||
inserted_member_fns() const;
|
||||
|
||||
const var_diff_sptrs_type&
|
||||
sorted_changed_data_members() const;
|
||||
|
||||
size_t
|
||||
count_filtered_changed_data_members(bool local_only = false) const;
|
||||
|
||||
@@ -2309,6 +2419,12 @@ public:
|
||||
/// A convenience typedef for a shared pointer to @ref diff_stats
|
||||
typedef shared_ptr<diff_stats> diff_stats_sptr;
|
||||
|
||||
bool
|
||||
do_log() const;
|
||||
|
||||
void
|
||||
do_log(bool);
|
||||
|
||||
corpus_sptr
|
||||
first_corpus() const;
|
||||
|
||||
@@ -2803,6 +2919,9 @@ is_class_or_union_diff(const diff* d);
|
||||
const class_or_union_diff*
|
||||
is_anonymous_class_or_union_diff(const diff* d);
|
||||
|
||||
const subrange_diff*
|
||||
is_subrange_diff(const diff* diff);
|
||||
|
||||
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-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
|
||||
|
||||
+19
-7
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
|
||||
@@ -48,7 +48,8 @@ public:
|
||||
ELF_ORIGIN = 1 << 1,
|
||||
DWARF_ORIGIN = 1 << 2,
|
||||
CTF_ORIGIN = 1 << 3,
|
||||
LINUX_KERNEL_BINARY_ORIGIN = 1 << 4
|
||||
BTF_ORIGIN = 1 << 4,
|
||||
LINUX_KERNEL_BINARY_ORIGIN = 1 << 5
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -68,6 +69,12 @@ public:
|
||||
const environment&
|
||||
get_environment() const;
|
||||
|
||||
bool
|
||||
do_log() const;
|
||||
|
||||
void
|
||||
do_log(bool);
|
||||
|
||||
void
|
||||
add(const translation_unit_sptr&);
|
||||
|
||||
@@ -211,7 +218,7 @@ public:
|
||||
virtual const functions&
|
||||
get_functions() const;
|
||||
|
||||
const vector<function_decl*>*
|
||||
const std::unordered_set<function_decl*>*
|
||||
lookup_functions(const string& id) const;
|
||||
|
||||
void
|
||||
@@ -295,13 +302,13 @@ operator&=(corpus::origin &l, corpus::origin r);
|
||||
/// parameters needed.
|
||||
class corpus::exported_decls_builder
|
||||
{
|
||||
class priv;
|
||||
std::unique_ptr<priv> priv_;
|
||||
|
||||
// Forbid default construction.
|
||||
exported_decls_builder();
|
||||
|
||||
public:
|
||||
class priv;
|
||||
std::unique_ptr<priv> priv_;
|
||||
|
||||
friend class corpus;
|
||||
|
||||
exported_decls_builder(functions& fns,
|
||||
@@ -320,6 +327,9 @@ public:
|
||||
functions&
|
||||
exported_functions();
|
||||
|
||||
std::unordered_set<function_decl*>*
|
||||
fn_id_maps_to_several_fns(function_decl*);
|
||||
|
||||
const variables&
|
||||
exported_variables() const;
|
||||
|
||||
@@ -327,7 +337,7 @@ public:
|
||||
exported_variables();
|
||||
|
||||
void
|
||||
maybe_add_fn_to_exported_fns(const function_decl*);
|
||||
maybe_add_fn_to_exported_fns(function_decl*);
|
||||
|
||||
void
|
||||
maybe_add_var_to_exported_vars(const var_decl*);
|
||||
@@ -356,6 +366,8 @@ public:
|
||||
|
||||
void add_corpus(const corpus_sptr&);
|
||||
|
||||
bool has_corpus(const string&);
|
||||
|
||||
const corpora_type&
|
||||
get_corpora() const;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2021-2022 Oracle, Inc.
|
||||
// Copyright (C) 2021-2023 Oracle, Inc.
|
||||
//
|
||||
// Author: Jose E. Marchesi
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2019-2022 Google, Inc.
|
||||
// Copyright (C) 2019-2023 Google, Inc.
|
||||
|
||||
/// @file
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
///
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2022 Red Hat, Inc.
|
||||
// Copyright (C) 2022-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -50,17 +50,21 @@ public:
|
||||
~elf_based_reader();
|
||||
|
||||
virtual void
|
||||
reset(const std::string& elf_path,
|
||||
const vector<char**>& debug_info_root_paths);
|
||||
initialize(const std::string& elf_path,
|
||||
const vector<char**>& debug_info_root_paths);
|
||||
|
||||
virtual ir::corpus_sptr
|
||||
read_and_add_corpus_to_group(ir::corpus_group& group,
|
||||
fe_iface::status& status);
|
||||
|
||||
virtual void
|
||||
initialize(const string& elf_path,
|
||||
const vector<char**>& debug_info_root_paths,
|
||||
bool load_all_types,
|
||||
bool linux_kernel_mode) = 0;
|
||||
|
||||
virtual void
|
||||
initialize(const std::string& corpus_path);
|
||||
};//end class elf_based_reader
|
||||
|
||||
typedef std::shared_ptr<elf_based_reader> elf_based_reader_sptr;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2022 Red Hat, Inc.
|
||||
// Copyright (C) 2022-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -72,9 +72,12 @@ class reader : public fe_iface
|
||||
|
||||
~reader();
|
||||
|
||||
void
|
||||
reset(const std::string& elf_path,
|
||||
const vector<char**>& debug_info_roots);
|
||||
virtual void
|
||||
initialize(const std::string& elf_path,
|
||||
const vector<char**>& debug_info_roots);
|
||||
|
||||
virtual void
|
||||
initialize(const std::string& elf_path);
|
||||
|
||||
const vector<char**>&
|
||||
debug_info_root_paths() const;
|
||||
@@ -97,6 +100,9 @@ class reader : public fe_iface
|
||||
bool
|
||||
has_ctf_debug_info() const;
|
||||
|
||||
bool
|
||||
has_btf_debug_info() const;
|
||||
|
||||
const Dwarf*
|
||||
alternate_dwarf_debug_info() const;
|
||||
|
||||
@@ -118,6 +124,9 @@ class reader : public fe_iface
|
||||
const Elf_Scn*
|
||||
find_alternate_ctf_section() const;
|
||||
|
||||
const Elf_Scn*
|
||||
find_btf_section() const;
|
||||
|
||||
const vector<string>&
|
||||
dt_needed()const;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2022 Red Hat, Inc.
|
||||
// Copyright (C) 2022-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -74,8 +74,8 @@ protected:
|
||||
|
||||
virtual ~fe_iface();
|
||||
|
||||
void
|
||||
reset(const std::string& corpus_path, environment& e);
|
||||
virtual void
|
||||
initialize(const std::string& corpus_path);
|
||||
|
||||
const options_type&
|
||||
options() const;
|
||||
|
||||
+148
-5
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
|
||||
@@ -11,12 +11,14 @@
|
||||
#include <stdint.h>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <regex.h>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility> // for std::rel_ops, at least.
|
||||
#include <vector>
|
||||
#include "abg-interned-str.h"
|
||||
@@ -54,10 +56,38 @@ using std::weak_ptr;
|
||||
using std::unordered_map;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::unordered_set;
|
||||
|
||||
typedef unordered_set<string> string_set_type;
|
||||
|
||||
// Pull in relational operators.
|
||||
using namespace std::rel_ops;
|
||||
|
||||
namespace comparison
|
||||
{
|
||||
class diff_context;
|
||||
|
||||
/// Convenience typedef for a shared pointer of @ref diff_context.
|
||||
typedef shared_ptr<diff_context> diff_context_sptr;
|
||||
|
||||
/// Convenience typedef for a weak pointer of @ref diff_context.
|
||||
typedef weak_ptr<diff_context> diff_context_wptr;
|
||||
|
||||
class diff;
|
||||
|
||||
/// Convenience typedef for a shared_ptr for the @ref diff class
|
||||
typedef shared_ptr<diff> diff_sptr;
|
||||
|
||||
/// Convenience typedef for a weak_ptr for the @ref diff class
|
||||
typedef weak_ptr<diff> diff_wptr;
|
||||
}
|
||||
|
||||
namespace regex
|
||||
{
|
||||
/// A convenience typedef for a shared pointer of regex_t.
|
||||
typedef std::shared_ptr<regex_t> regex_t_sptr;
|
||||
}// end namespace regex
|
||||
|
||||
namespace ir
|
||||
{
|
||||
|
||||
@@ -162,6 +192,9 @@ typedef shared_ptr<class_decl> class_decl_sptr;
|
||||
/// Convenience typedef for a vector of @ref class_decl_sptr
|
||||
typedef vector<class_decl_sptr> classes_type;
|
||||
|
||||
/// Convenience typedef for a vector of @ref class_or_union_sptr
|
||||
typedef vector<class_or_union_sptr> classes_or_unions_type;
|
||||
|
||||
/// Convenience typedef for a weak pointer on a @ref class_decl.
|
||||
typedef weak_ptr<class_decl> class_decl_wptr;
|
||||
|
||||
@@ -418,6 +451,9 @@ is_integral_type(const type_or_decl_base_sptr&);
|
||||
typedef_decl_sptr
|
||||
is_typedef(const type_or_decl_base_sptr);
|
||||
|
||||
const typedef_decl*
|
||||
is_typedef(const type_or_decl_base*);
|
||||
|
||||
const typedef_decl*
|
||||
is_typedef(const type_base*);
|
||||
|
||||
@@ -445,11 +481,22 @@ is_class_type(const type_or_decl_base*);
|
||||
class_decl_sptr
|
||||
is_class_type(const type_or_decl_base_sptr&);
|
||||
|
||||
bool
|
||||
is_declaration_only_class_or_union_type(const type_base *t);
|
||||
var_decl_sptr
|
||||
has_flexible_array_data_member(const class_decl&);
|
||||
|
||||
var_decl_sptr
|
||||
has_flexible_array_data_member(const class_decl*);
|
||||
|
||||
var_decl_sptr
|
||||
has_flexible_array_data_member(const class_decl_sptr&);
|
||||
|
||||
bool
|
||||
is_declaration_only_class_or_union_type(const type_base_sptr&);
|
||||
is_declaration_only_class_or_union_type(const type_base *t,
|
||||
bool look_through_decl_only = false);
|
||||
|
||||
bool
|
||||
is_declaration_only_class_or_union_type(const type_base_sptr& t,
|
||||
bool look_through_decl_only = false);
|
||||
|
||||
class_or_union*
|
||||
is_class_or_union_type(const type_or_decl_base*);
|
||||
@@ -457,6 +504,14 @@ is_class_or_union_type(const type_or_decl_base*);
|
||||
class_or_union_sptr
|
||||
is_class_or_union_type(const type_or_decl_base_sptr&);
|
||||
|
||||
bool
|
||||
class_or_union_types_of_same_kind(const class_or_union *,
|
||||
const class_or_union*);
|
||||
|
||||
bool
|
||||
class_or_union_types_of_same_kind(const class_or_union_sptr&,
|
||||
const class_or_union_sptr&);
|
||||
|
||||
bool
|
||||
is_union_type(const type_or_decl_base&);
|
||||
|
||||
@@ -481,6 +536,9 @@ is_pointer_type(const type_or_decl_base*);
|
||||
pointer_type_def_sptr
|
||||
is_pointer_type(const type_or_decl_base_sptr&);
|
||||
|
||||
bool
|
||||
is_typedef_ptr_or_ref_to_decl_only_class_or_union_type(const type_base* t);
|
||||
|
||||
reference_type_def*
|
||||
is_reference_type(type_or_decl_base*);
|
||||
|
||||
@@ -493,6 +551,15 @@ is_reference_type(const type_or_decl_base_sptr&);
|
||||
const type_base*
|
||||
is_void_pointer_type(const type_base*);
|
||||
|
||||
const type_base_sptr
|
||||
is_void_pointer_type(const type_base_sptr&);
|
||||
|
||||
const type_base*
|
||||
is_void_pointer_type_equivalent(const type_base*);
|
||||
|
||||
const type_base*
|
||||
is_void_pointer_type_equivalent(const type_base&);
|
||||
|
||||
qualified_type_def*
|
||||
is_qualified_type(const type_or_decl_base*);
|
||||
|
||||
@@ -648,6 +715,12 @@ is_data_member(const decl_base *);
|
||||
const var_decl_sptr
|
||||
get_next_data_member(const class_or_union_sptr&, const var_decl_sptr&);
|
||||
|
||||
var_decl_sptr
|
||||
get_last_data_member(const class_or_union&);
|
||||
|
||||
var_decl_sptr
|
||||
get_last_data_member(const class_or_union*);
|
||||
|
||||
var_decl_sptr
|
||||
get_last_data_member(const class_or_union_sptr&);
|
||||
|
||||
@@ -675,6 +748,15 @@ is_anonymous_data_member(const var_decl*);
|
||||
bool
|
||||
is_anonymous_data_member(const var_decl&);
|
||||
|
||||
bool
|
||||
is_data_member_of_anonymous_class_or_union(const var_decl&);
|
||||
|
||||
bool
|
||||
is_data_member_of_anonymous_class_or_union(const var_decl*);
|
||||
|
||||
bool
|
||||
is_data_member_of_anonymous_class_or_union(const var_decl_sptr&);
|
||||
|
||||
const var_decl_sptr
|
||||
get_first_non_anonymous_data_member(const var_decl_sptr);
|
||||
|
||||
@@ -688,8 +770,12 @@ anonymous_data_member_to_class_or_union(const var_decl*);
|
||||
class_or_union_sptr
|
||||
anonymous_data_member_to_class_or_union(const var_decl_sptr&);
|
||||
|
||||
class_or_union_sptr
|
||||
anonymous_data_member_to_class_or_union(const var_decl&);
|
||||
|
||||
bool
|
||||
scope_anonymous_or_typedef_named(const decl_base&);
|
||||
anonymous_data_member_exists_in_class(const var_decl& anon_dm,
|
||||
const class_or_union& clazz);
|
||||
|
||||
bool
|
||||
is_anonymous_or_typedef_named(const decl_base&);
|
||||
@@ -733,6 +819,11 @@ get_data_member_offset(const decl_base_sptr);
|
||||
uint64_t
|
||||
get_absolute_data_member_offset(const var_decl&);
|
||||
|
||||
bool
|
||||
get_next_data_member_offset(const class_or_union*,
|
||||
const var_decl_sptr&,
|
||||
uint64_t&);
|
||||
|
||||
bool
|
||||
get_next_data_member_offset(const class_or_union_sptr&,
|
||||
const var_decl_sptr&,
|
||||
@@ -960,6 +1051,9 @@ get_function_type_name(const function_type*, bool internal = false);
|
||||
interned_string
|
||||
get_function_type_name(const function_type&, bool internal = false);
|
||||
|
||||
interned_string
|
||||
get_function_id_or_pretty_representation(function_decl *fn);
|
||||
|
||||
interned_string
|
||||
get_method_type_name(const method_type_sptr&, bool internal = false);
|
||||
|
||||
@@ -1029,6 +1123,33 @@ get_class_or_union_flat_representation(const class_or_union_sptr& cou,
|
||||
bool internal,
|
||||
bool qualified_name = true);
|
||||
|
||||
string
|
||||
get_enum_flat_representation(const enum_type_decl& enum_type,
|
||||
const string& indent,
|
||||
bool one_line,
|
||||
bool internal,
|
||||
bool qualified_names);
|
||||
|
||||
string
|
||||
get_enum_flat_representation(const enum_type_decl* enum_type,
|
||||
const string& indent,
|
||||
bool one_line,
|
||||
bool internal,
|
||||
bool qualified_names);
|
||||
|
||||
string
|
||||
get_enum_flat_representation(const enum_type_decl_sptr& enum_type,
|
||||
const string& indent,
|
||||
bool one_line,
|
||||
bool qualified_names);
|
||||
|
||||
string
|
||||
get_class_or_enum_flat_representation(const type_base& coe,
|
||||
const string& indent,
|
||||
bool one_line,
|
||||
bool internal,
|
||||
bool qualified_name);
|
||||
|
||||
string
|
||||
get_debug_representation(const type_or_decl_base*);
|
||||
|
||||
@@ -1056,6 +1177,9 @@ debug(const decl_base* artifact);
|
||||
bool
|
||||
debug_equals(const type_or_decl_base *l, const type_or_decl_base *r);
|
||||
|
||||
void
|
||||
debug_comp_stack(const environment& env);
|
||||
|
||||
bool
|
||||
odr_is_relevant(const type_or_decl_base&);
|
||||
|
||||
@@ -1137,6 +1261,9 @@ lookup_class_type(const interned_string&, const corpus&);
|
||||
const type_base_wptrs_type*
|
||||
lookup_class_types(const interned_string&, const corpus&);
|
||||
|
||||
const type_base_wptrs_type*
|
||||
lookup_union_types(const interned_string&, const corpus&);
|
||||
|
||||
bool
|
||||
lookup_decl_only_class_types(const interned_string&,
|
||||
const corpus&,
|
||||
@@ -1145,6 +1272,9 @@ lookup_decl_only_class_types(const interned_string&,
|
||||
const type_base_wptrs_type*
|
||||
lookup_class_types(const string&, const corpus&);
|
||||
|
||||
const type_base_wptrs_type*
|
||||
lookup_union_types(const string&, const corpus&);
|
||||
|
||||
class_decl_sptr
|
||||
lookup_class_type_per_location(const interned_string&, const corpus&);
|
||||
|
||||
@@ -1414,6 +1544,12 @@ is_non_canonicalized_type(const type_base *);
|
||||
bool
|
||||
is_non_canonicalized_type(const type_base_sptr&);
|
||||
|
||||
bool
|
||||
is_unique_type(const type_base_sptr&);
|
||||
|
||||
bool
|
||||
is_unique_type(const type_base*);
|
||||
|
||||
/// For a given type, return its exemplar type.
|
||||
///
|
||||
/// For a given type, its exemplar type is either its canonical type
|
||||
@@ -1445,6 +1581,13 @@ build_internal_underlying_enum_type_name(const string &base_name,
|
||||
bool is_anonymous,
|
||||
uint64_t size);
|
||||
|
||||
var_decl_sptr
|
||||
find_first_data_member_matching_regexp(const class_or_union& t,
|
||||
const regex::regex_t_sptr& r);
|
||||
|
||||
var_decl_sptr
|
||||
find_last_data_member_matching_regexp(const class_or_union& t,
|
||||
const regex::regex_t_sptr& regex);
|
||||
} // end namespace ir
|
||||
|
||||
using namespace abigail::ir;
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2016-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2016-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
|
||||
+101
-13
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -162,9 +162,15 @@ public:
|
||||
const type_base_sptr&
|
||||
get_void_type() const;
|
||||
|
||||
const type_base_sptr&
|
||||
get_void_pointer_type() const;
|
||||
|
||||
const type_base_sptr&
|
||||
get_variadic_parameter_type() const;
|
||||
|
||||
static string&
|
||||
get_variadic_parameter_type_name();
|
||||
|
||||
bool
|
||||
canonicalization_is_done() const;
|
||||
|
||||
@@ -189,6 +195,12 @@ public:
|
||||
bool
|
||||
is_void_type(const type_base*) const;
|
||||
|
||||
bool
|
||||
is_void_pointer_type(const type_base_sptr&) const;
|
||||
|
||||
bool
|
||||
is_void_pointer_type(const type_base*) const;
|
||||
|
||||
bool
|
||||
is_variadic_parameter_type(const type_base*) const;
|
||||
|
||||
@@ -244,17 +256,26 @@ public:
|
||||
type_base* get_canonical_type(const char* name, unsigned index);
|
||||
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
unordered_map<string, uintptr_t>&
|
||||
const unordered_map<string, uintptr_t>&
|
||||
get_type_id_canonical_type_map() const;
|
||||
|
||||
unordered_map<string, uintptr_t>&
|
||||
get_type_id_canonical_type_map();
|
||||
|
||||
const unordered_map<uintptr_t, string>&
|
||||
get_pointer_type_id_map() const;
|
||||
|
||||
unordered_map<uintptr_t, string>&
|
||||
get_pointer_type_id_map();
|
||||
|
||||
string
|
||||
get_type_id_from_pointer(uintptr_t ptr);
|
||||
get_type_id_from_pointer(uintptr_t ptr) const;
|
||||
|
||||
string
|
||||
get_type_id_from_type(const type_base *ptr) const;
|
||||
|
||||
uintptr_t
|
||||
get_canonical_type_from_type_id(const char*);
|
||||
get_canonical_type_from_type_id(const char*) const;
|
||||
#endif
|
||||
|
||||
friend class class_or_union;
|
||||
@@ -537,6 +558,10 @@ typedef unordered_set<const type_or_decl_base*,
|
||||
/// value is a @ref type_base_wptr.
|
||||
typedef unordered_map<string, type_base_wptr> string_type_base_wptr_map_type;
|
||||
|
||||
/// A 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_type;
|
||||
|
||||
/// A convenience typedef for a map which key is an @ref
|
||||
/// interned_string and which value is a @ref type_base_wptr.
|
||||
typedef unordered_map<interned_string, type_base_wptr, hash_interned_string>
|
||||
@@ -1090,6 +1115,9 @@ public:
|
||||
elf_symbol_sptr
|
||||
get_alias_which_equals(const elf_symbol& other) const;
|
||||
|
||||
elf_symbol_sptr
|
||||
get_alias_with_default_symbol_version() const;
|
||||
|
||||
string
|
||||
get_aliases_id_string(const string_elf_symbols_map_type& symtab,
|
||||
bool include_symbol_itself = true) const;
|
||||
@@ -1684,15 +1712,15 @@ public:
|
||||
void
|
||||
set_is_declaration_only(bool f);
|
||||
|
||||
friend type_base_sptr
|
||||
canonicalize(type_base_sptr);
|
||||
|
||||
friend bool
|
||||
equals(const decl_base&, const decl_base&, change_kind*);
|
||||
|
||||
friend bool
|
||||
equals(const var_decl&, const var_decl&, change_kind*);
|
||||
|
||||
friend bool
|
||||
var_equals_modulo_types(const var_decl&, const var_decl&, change_kind*);
|
||||
|
||||
friend bool
|
||||
maybe_compare_as_member_decls(const decl_base& l,
|
||||
const decl_base& r,
|
||||
@@ -1884,9 +1912,6 @@ public:
|
||||
|
||||
friend void
|
||||
remove_decl_from_scope(decl_base_sptr decl);
|
||||
|
||||
friend type_base_sptr
|
||||
canonicalize(type_base_sptr);
|
||||
};//end class scope_decl
|
||||
|
||||
bool
|
||||
@@ -2093,7 +2118,14 @@ public:
|
||||
virtual bool
|
||||
operator==(const type_decl&) const;
|
||||
|
||||
bool operator!=(const type_decl&)const;
|
||||
virtual bool
|
||||
operator!=(const type_base&)const;
|
||||
|
||||
virtual bool
|
||||
operator!=(const decl_base&)const;
|
||||
|
||||
virtual bool
|
||||
operator!=(const type_decl&)const;
|
||||
|
||||
virtual void
|
||||
get_qualified_name(interned_string& qualified_name,
|
||||
@@ -2353,8 +2385,8 @@ equals(const reference_type_def&, const reference_type_def&, change_kind*);
|
||||
/// Abstracts a reference type.
|
||||
class reference_type_def : public virtual type_base, public virtual decl_base
|
||||
{
|
||||
type_base_wptr pointed_to_type_;
|
||||
bool is_lvalue_;
|
||||
struct priv;
|
||||
std::unique_ptr<priv> priv_;
|
||||
|
||||
// Forbidden.
|
||||
reference_type_def();
|
||||
@@ -2553,6 +2585,12 @@ public:
|
||||
bool
|
||||
operator==(const subrange_type& o) const;
|
||||
|
||||
bool
|
||||
operator!=(const decl_base& o) const;
|
||||
|
||||
bool
|
||||
operator!=(const type_base& o) const;
|
||||
|
||||
bool
|
||||
operator!=(const subrange_type& o) const;
|
||||
|
||||
@@ -2635,6 +2673,11 @@ is_subrange_type(const type_or_decl_base *type);
|
||||
array_type_def::subrange_sptr
|
||||
is_subrange_type(const type_or_decl_base_sptr &type);
|
||||
|
||||
bool
|
||||
equals(const array_type_def::subrange_type&,
|
||||
const array_type_def::subrange_type&,
|
||||
change_kind*);
|
||||
|
||||
bool
|
||||
equals(const enum_type_decl&, const enum_type_decl&, change_kind*);
|
||||
|
||||
@@ -2685,6 +2728,9 @@ public:
|
||||
const enumerators&
|
||||
get_enumerators() const;
|
||||
|
||||
const enumerators&
|
||||
get_sorted_enumerators() const;
|
||||
|
||||
enumerators&
|
||||
get_enumerators();
|
||||
|
||||
@@ -2767,6 +2813,10 @@ public:
|
||||
set_enum_type(enum_type_decl*);
|
||||
}; // end class enum_type_def::enumerator
|
||||
|
||||
bool
|
||||
is_enumerator_present_in_enum(const enum_type_decl::enumerator &enr,
|
||||
const enum_type_decl &enom);
|
||||
|
||||
bool
|
||||
equals(const typedef_decl&, const typedef_decl&, change_kind*);
|
||||
|
||||
@@ -2818,6 +2868,13 @@ public:
|
||||
void
|
||||
set_underlying_type(const type_base_sptr&);
|
||||
|
||||
virtual void
|
||||
get_qualified_name(interned_string& qualified_name,
|
||||
bool internal = false) const;
|
||||
|
||||
virtual const interned_string&
|
||||
get_qualified_name(bool internal = false) const;
|
||||
|
||||
virtual bool
|
||||
traverse(ir_node_visitor&);
|
||||
|
||||
@@ -2876,6 +2933,9 @@ public:
|
||||
bool
|
||||
equals(const var_decl&, const var_decl&, change_kind*);
|
||||
|
||||
bool
|
||||
var_equals_modulo_types(const var_decl&, const var_decl&, change_kind*);
|
||||
|
||||
bool
|
||||
equals_modulo_cv_qualifier(const array_type_def*, const array_type_def*);
|
||||
|
||||
@@ -2912,6 +2972,9 @@ public:
|
||||
const type_base_sptr
|
||||
get_type() const;
|
||||
|
||||
void
|
||||
set_type(type_base_sptr&);
|
||||
|
||||
const type_base*
|
||||
get_naked_type() const;
|
||||
|
||||
@@ -3431,6 +3494,9 @@ public:
|
||||
const std::list<template_parameter_sptr>&
|
||||
get_template_parameters() const;
|
||||
|
||||
virtual bool
|
||||
operator==(const decl_base& o) const;
|
||||
|
||||
virtual bool
|
||||
operator==(const template_decl& o) const;
|
||||
|
||||
@@ -3507,6 +3573,12 @@ public:
|
||||
virtual bool
|
||||
operator==(const type_base&) const;
|
||||
|
||||
virtual bool
|
||||
operator==(const type_decl&) const;
|
||||
|
||||
virtual bool
|
||||
operator==(const decl_base&) const;
|
||||
|
||||
virtual bool
|
||||
operator==(const template_parameter&) const;
|
||||
|
||||
@@ -3585,6 +3657,9 @@ public:
|
||||
virtual bool
|
||||
operator==(const type_base&) const;
|
||||
|
||||
virtual bool
|
||||
operator==(const decl_base&) const;
|
||||
|
||||
virtual bool
|
||||
operator==(const template_parameter&) const;
|
||||
|
||||
@@ -4205,6 +4280,9 @@ public:
|
||||
virtual bool
|
||||
operator==(const type_base&) const;
|
||||
|
||||
virtual bool
|
||||
operator==(const class_or_union&) const;
|
||||
|
||||
virtual bool
|
||||
operator==(const class_decl&) const;
|
||||
|
||||
@@ -4376,6 +4454,9 @@ public:
|
||||
virtual bool
|
||||
operator==(const type_base&) const;
|
||||
|
||||
virtual bool
|
||||
operator==(const class_or_union&) const;
|
||||
|
||||
virtual bool
|
||||
operator==(const union_decl&) const;
|
||||
|
||||
@@ -4545,6 +4626,10 @@ const var_decl*
|
||||
lookup_data_member(const type_base* type,
|
||||
const char* dm_name);
|
||||
|
||||
const var_decl_sptr
|
||||
lookup_data_member(const type_base_sptr& type,
|
||||
const var_decl_sptr& dm);
|
||||
|
||||
const function_decl::parameter*
|
||||
get_function_parameter(const decl_base* fun,
|
||||
unsigned parm_num);
|
||||
@@ -4635,6 +4720,9 @@ public:
|
||||
virtual bool
|
||||
operator==(const member_base& o) const;
|
||||
|
||||
virtual bool
|
||||
operator==(const decl_base&) const;
|
||||
|
||||
virtual bool
|
||||
operator==(const member_class_template&) const;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 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-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
///
|
||||
|
||||
+19
-1
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2017-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2017-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -32,6 +32,7 @@ class qualified_type_diff;
|
||||
class distinct_diff;
|
||||
class pointer_diff;
|
||||
class reference_diff;
|
||||
class subrange_diff;
|
||||
class array_diff;
|
||||
class base_diff;
|
||||
class class_or_union_diff;
|
||||
@@ -92,6 +93,10 @@ public:
|
||||
report(const array_diff& d, std::ostream& out,
|
||||
const std::string& indent = "") const = 0;
|
||||
|
||||
virtual void
|
||||
report(const subrange_diff& d, std::ostream& out,
|
||||
const std::string& indent = "") const = 0;
|
||||
|
||||
virtual void
|
||||
report(const base_diff& d, std::ostream& out,
|
||||
const std::string& indent = "") const = 0;
|
||||
@@ -173,6 +178,11 @@ public:
|
||||
std::ostream& out,
|
||||
const std::string& indent) const;
|
||||
|
||||
void
|
||||
report_underlying_changes_of_qualified_type (const qualified_type_diff& d,
|
||||
ostream& out,
|
||||
const string& indent) const;
|
||||
|
||||
virtual void
|
||||
report(const qualified_type_diff& d, std::ostream& out,
|
||||
const std::string& indent = "") const;
|
||||
@@ -203,6 +213,10 @@ public:
|
||||
report(const function_type_diff& d, std::ostream& out,
|
||||
const std::string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const subrange_diff& d, std::ostream& out,
|
||||
const std::string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const array_diff& d, std::ostream& out,
|
||||
const std::string& indent = "") const;
|
||||
@@ -285,6 +299,10 @@ public:
|
||||
report(const function_type_diff& d, std::ostream& out,
|
||||
const std::string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const subrange_diff& d, std::ostream& out,
|
||||
const std::string& indent = "") const;
|
||||
|
||||
virtual void
|
||||
report(const array_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-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
///
|
||||
|
||||
+136
-9
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2016-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2016-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <unordered_set>
|
||||
|
||||
#include "abg-ini.h"
|
||||
#include "abg-comparison.h"
|
||||
#include "abg-ir.h"
|
||||
|
||||
namespace abigail
|
||||
{
|
||||
@@ -29,15 +29,24 @@ class fe_iface;
|
||||
/// that are defined in this namespace.
|
||||
namespace suppr
|
||||
{
|
||||
|
||||
using namespace abigail::comparison;
|
||||
using std::unordered_set;
|
||||
using std::string;
|
||||
using std::shared_ptr;
|
||||
using std::vector;
|
||||
using comparison::diff;
|
||||
using comparison::diff_context_sptr;
|
||||
|
||||
/// Base type of the suppression specifications types.
|
||||
/// Base type of a direct suppression specifications types.
|
||||
///
|
||||
/// This abstracts a suppression specification. It's a way to specify
|
||||
/// how to drop reports about a particular diff node on the floor, if
|
||||
/// it matches the supppression specification.
|
||||
///
|
||||
/// Note that a direct suppression specification suppresses (for
|
||||
/// reporting purposes) the diff node that it matches. A negated
|
||||
/// suppression specification, however, suppresses a diff node that it
|
||||
/// DOES NOT match. A Negated suppression specification is abstracted
|
||||
/// by the class @ref negated_suppression_base.
|
||||
class suppression_base
|
||||
{
|
||||
public:
|
||||
@@ -140,6 +149,36 @@ typedef shared_ptr<type_suppression> type_suppression_sptr;
|
||||
/// Convenience typedef for vector of @ref type_suppression_sptr.
|
||||
typedef vector<type_suppression_sptr> type_suppressions_type;
|
||||
|
||||
/// The base class of suppression specifications that are defined by
|
||||
/// the negation of matching clauses.
|
||||
///
|
||||
/// A direct suppression specification suppresses (for reporting
|
||||
/// purposes) the diff node that it matches. A negated suppression
|
||||
/// specification suppresses a diff node that it DOES NOT match.
|
||||
class negated_suppression_base
|
||||
{
|
||||
public:
|
||||
negated_suppression_base();
|
||||
|
||||
virtual ~negated_suppression_base();
|
||||
}; // end class negated_suppression_base.
|
||||
|
||||
/// A convenience typedef for a shared pointer to @ref
|
||||
/// negated_suppression_base.
|
||||
typedef shared_ptr<negated_suppression_base> negated_suppression_sptr;
|
||||
|
||||
/// Convenience typedef for a vector of @ref negated_suppression_sptr
|
||||
typedef vector<negated_suppression_sptr> negated_suppressions_type;
|
||||
|
||||
bool
|
||||
is_negated_suppression(const suppression_base&);
|
||||
|
||||
const negated_suppression_base*
|
||||
is_negated_suppression(const suppression_base*);
|
||||
|
||||
negated_suppression_sptr
|
||||
is_negated_suppression(const suppression_sptr&);
|
||||
|
||||
/// Abstraction of a type suppression specification.
|
||||
///
|
||||
/// Specifies under which condition reports about a type diff node
|
||||
@@ -243,6 +282,24 @@ public:
|
||||
void
|
||||
set_reach_kind(reach_kind k);
|
||||
|
||||
bool
|
||||
get_has_size_change() const;
|
||||
|
||||
void
|
||||
set_has_size_change(bool flag);
|
||||
|
||||
const string_set_type&
|
||||
get_potential_data_member_names() const;
|
||||
|
||||
void
|
||||
set_potential_data_member_names(const string_set_type&) const;
|
||||
|
||||
const string&
|
||||
get_potential_data_member_names_regex_str() const;
|
||||
|
||||
void
|
||||
set_potential_data_member_names_regex_str(const string&) const;
|
||||
|
||||
void
|
||||
set_data_member_insertion_ranges(const insertion_ranges& r);
|
||||
|
||||
@@ -273,6 +330,12 @@ public:
|
||||
void
|
||||
set_changed_enumerator_names(const vector<string>&);
|
||||
|
||||
const vector<regex::regex_t_sptr>&
|
||||
get_changed_enumerators_regexp() const;
|
||||
|
||||
void
|
||||
set_changed_enumerators_regexp(const vector<regex::regex_t_sptr>&);
|
||||
|
||||
virtual bool
|
||||
suppresses_diff(const diff* diff) const;
|
||||
|
||||
@@ -303,6 +366,7 @@ public:
|
||||
class boundary;
|
||||
class integer_boundary;
|
||||
class fn_call_expr_boundary;
|
||||
class named_boundary;
|
||||
|
||||
/// Convenience typedef for a shared_ptr to @ref boundary
|
||||
typedef shared_ptr<boundary> boundary_sptr;
|
||||
@@ -314,6 +378,10 @@ public:
|
||||
/// fn_call_expr_boundary
|
||||
typedef shared_ptr<fn_call_expr_boundary> fn_call_expr_boundary_sptr;
|
||||
|
||||
/// Convenience typedef for a shared_ptr to a @ref
|
||||
/// named_boundary
|
||||
typedef shared_ptr<named_boundary> named_boundary_sptr;
|
||||
|
||||
insertion_range();
|
||||
|
||||
insertion_range(boundary_sptr begin, boundary_sptr end);
|
||||
@@ -321,7 +389,7 @@ public:
|
||||
boundary_sptr
|
||||
begin() const;
|
||||
|
||||
boundary_sptr
|
||||
boundary_sptr
|
||||
end() const;
|
||||
|
||||
static insertion_range::integer_boundary_sptr
|
||||
@@ -333,10 +401,13 @@ public:
|
||||
static insertion_range::fn_call_expr_boundary_sptr
|
||||
create_fn_call_expr_boundary(const string&);
|
||||
|
||||
static insertion_range::named_boundary_sptr
|
||||
create_named_boundary(const string&);
|
||||
|
||||
static bool
|
||||
eval_boundary(boundary_sptr boundary,
|
||||
class_decl_sptr context,
|
||||
uint64_t& value);
|
||||
eval_boundary(const boundary_sptr boundary,
|
||||
const class_or_union* context,
|
||||
uint64_t& value);
|
||||
|
||||
static bool
|
||||
boundary_value_is_end(uint64_t value);
|
||||
@@ -348,6 +419,9 @@ is_integer_boundary(type_suppression::insertion_range::boundary_sptr);
|
||||
type_suppression::insertion_range::fn_call_expr_boundary_sptr
|
||||
is_fn_call_expr_boundary(type_suppression::insertion_range::boundary_sptr);
|
||||
|
||||
type_suppression::insertion_range::named_boundary_sptr
|
||||
is_named_boundary(type_suppression::insertion_range::boundary_sptr);
|
||||
|
||||
/// The abstraction of the boundary of an @ref insertion_range, in the
|
||||
/// context of a @ref type_suppression
|
||||
class type_suppression::insertion_range::boundary
|
||||
@@ -395,6 +469,53 @@ public:
|
||||
~fn_call_expr_boundary();
|
||||
}; //end class type_suppression::insertion_range::fn_call_expr_boundary
|
||||
|
||||
/// An @ref insertion_range boundary that is expressed as a named
|
||||
/// constant that is to be evaluated later in the context of a given
|
||||
/// type and resolved to a bit offset.
|
||||
class type_suppression::insertion_range::named_boundary
|
||||
: public type_suppression::insertion_range::boundary
|
||||
{
|
||||
struct priv;
|
||||
std::unique_ptr<priv> priv_;
|
||||
|
||||
named_boundary();
|
||||
|
||||
public:
|
||||
named_boundary(const string& name);
|
||||
const string& get_name() const;
|
||||
}; //end class type_suppression::insertion_range::named_boundary
|
||||
|
||||
/// Abstraction of a negated type suppression specification.
|
||||
///
|
||||
/// A negated type suppression suppresses a type if the negation of
|
||||
/// the equivalent propositions for a @ref type_suppression are valid.
|
||||
class negated_type_suppression : virtual public type_suppression,
|
||||
virtual public negated_suppression_base
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
negated_type_suppression(const string& label,
|
||||
const string& type_name_regexp,
|
||||
const string& type_name);
|
||||
|
||||
virtual bool
|
||||
suppresses_diff(const diff* diff) const;
|
||||
|
||||
bool
|
||||
suppresses_type(const type_base_sptr& type,
|
||||
const diff_context_sptr& ctxt) const;
|
||||
|
||||
bool
|
||||
suppresses_type(const type_base_sptr& type) const;
|
||||
|
||||
bool
|
||||
suppresses_type(const type_base_sptr& type,
|
||||
const scope_decl* type_scope) const;
|
||||
|
||||
virtual ~negated_type_suppression();
|
||||
};// end class negated_type_suppression
|
||||
|
||||
class function_suppression;
|
||||
|
||||
/// Convenience typedef for a shared pointer to function_suppression.
|
||||
@@ -887,6 +1008,12 @@ is_type_suppressed(const fe_iface& fe,
|
||||
const location& type_location,
|
||||
bool& type_is_private,
|
||||
bool require_drop_property = false);
|
||||
|
||||
bool
|
||||
is_data_member_offset_in_range(const var_decl_sptr&,
|
||||
const type_suppression::insertion_range_sptr&,
|
||||
const class_or_union*);
|
||||
|
||||
} // end namespace suppr
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
///@file
|
||||
|
||||
@@ -30,10 +30,12 @@ using std::string;
|
||||
using std::set;
|
||||
using std::shared_ptr;
|
||||
|
||||
void initialize();
|
||||
const char* get_system_libdir();
|
||||
const char* get_anonymous_struct_internal_name_prefix();
|
||||
const char* get_anonymous_union_internal_name_prefix();
|
||||
const char* get_anonymous_enum_internal_name_prefix();
|
||||
const char* get_anonymous_subrange_internal_name_prefix();
|
||||
|
||||
bool file_exists(const string&);
|
||||
bool is_regular_file(const string&);
|
||||
@@ -41,6 +43,8 @@ bool file_has_dwarf_debug_info(const string& elf_file_path,
|
||||
const vector<char**>& debug_info_root_paths);
|
||||
bool file_has_ctf_debug_info(const string& elf_file_path,
|
||||
const vector<char**>& debug_info_root_paths);
|
||||
bool file_has_btf_debug_info(const string& elf_file_path,
|
||||
const vector<char**>& debug_info_root_paths);
|
||||
bool is_dir(const string&);
|
||||
bool dir_exists(const string&);
|
||||
bool dir_is_empty(const string &);
|
||||
@@ -68,6 +72,9 @@ bool sorted_strings_common_prefix(vector<string>&, string&);
|
||||
string get_library_version_string();
|
||||
string get_abixml_version_string();
|
||||
bool execute_command_and_get_output(const string&, vector<string>&);
|
||||
void get_comma_separated_args_of_option(const string& input_str,
|
||||
const string& option,
|
||||
vector<string>& arguments);
|
||||
bool get_dsos_provided_by_rpm(const string& rpm_path,
|
||||
set<string>& provided_dsos);
|
||||
string trim_white_space(const string&);
|
||||
@@ -122,6 +129,38 @@ find_file_under_dir(const string& root_dir,
|
||||
const string& file_path_to_look_for,
|
||||
string& result);
|
||||
|
||||
bool
|
||||
find_file_under_dirs(const vector<string>& root_dirs,
|
||||
const string& file_path_to_look_for,
|
||||
string& result);
|
||||
|
||||
bool
|
||||
get_dependencies(const corpus&, const vector<string>&, set<string>&);
|
||||
|
||||
void
|
||||
add_binaries_into_corpus_group(const fe_iface_sptr& reader,
|
||||
const vector<string>& binaries,
|
||||
const vector<string>& deps_dirs,
|
||||
corpus_group& group);
|
||||
|
||||
void
|
||||
add_dependencies_into_corpus_group(const fe_iface_sptr& reader,
|
||||
const corpus& korpus,
|
||||
const vector<string>& deps_dirs,
|
||||
corpus_group& group);
|
||||
|
||||
corpus_group_sptr
|
||||
stick_corpus_and_binaries_into_corpus_group(const fe_iface_sptr& reader,
|
||||
const corpus_sptr& korpus,
|
||||
const vector<string>& binaries,
|
||||
const vector<string>& deps_dirs);
|
||||
|
||||
corpus_group_sptr
|
||||
stick_corpus_and_dependencies_into_corpus_group(const fe_iface_sptr& reader,
|
||||
const corpus_sptr& korpus,
|
||||
const vector<string>& deps_dirs);
|
||||
|
||||
|
||||
class temp_file;
|
||||
|
||||
/// Convenience typedef for a shared_ptr to @ref temp_file.
|
||||
@@ -298,6 +337,10 @@ bool
|
||||
file_is_kernel_package(const string& file_path,
|
||||
file_type file_type);
|
||||
|
||||
bool
|
||||
rpm_contains_file(const string& rpm_path,
|
||||
const string& file_name);
|
||||
|
||||
bool
|
||||
file_is_kernel_debuginfo_package(const string& file_path,
|
||||
file_type file_type);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 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 "2"
|
||||
#define ABIGAIL_VERSION_MINOR "4"
|
||||
#define ABIGAIL_VERSION_REVISION "0"
|
||||
#define ABIGAIL_VERSION_SUFFIX ""
|
||||
#define ABIGAIL_ABIXML_VERSION_MAJOR "2"
|
||||
#define ABIGAIL_ABIXML_VERSION_MINOR "1"
|
||||
#define ABIGAIL_ABIXML_VERSION_MINOR "2"
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
|
||||
@@ -48,6 +48,10 @@ if CTF_READER
|
||||
libabigail_la_SOURCES += abg-ctf-reader.cc
|
||||
endif
|
||||
|
||||
if BTF_READER
|
||||
libabigail_la_SOURCES += abg-btf-reader.cc
|
||||
endif
|
||||
|
||||
libabigail_la_LIBADD = $(DEPS_LIBS) $(FTS_LIBS)
|
||||
libabigail_la_LDFLAGS = -lpthread -Wl,--as-needed -no-undefined -version-info $(LIBABIGAIL_SO_CURRENT):$(LIBABIGAIL_SO_REVISION):$(LIBABIGAIL_SO_AGE)
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+96
-51
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -41,7 +41,7 @@ void
|
||||
apply_filter(filter_base& filter, corpus_diff_sptr d)
|
||||
{
|
||||
bool s = d->context()->visiting_a_node_twice_is_forbidden();
|
||||
d->context()->forbid_visiting_a_node_twice(false);
|
||||
d->context()->forbid_visiting_a_node_twice(true);
|
||||
d->traverse(filter);
|
||||
d->context()->forbid_visiting_a_node_twice(s);
|
||||
}
|
||||
@@ -633,6 +633,85 @@ has_data_member_replaced_by_anon_dm(const diff* diff)
|
||||
return !c->data_members_replaced_by_adms().empty();
|
||||
}
|
||||
|
||||
/// Test if we are looking at two variables which types are both one
|
||||
/// dimension array, with one of them being of unknow size and the two
|
||||
/// variables having the same symbol size.
|
||||
///
|
||||
/// This can happen in the case of these two declarations, for instance:
|
||||
///
|
||||
/// unsigned int array[];
|
||||
///
|
||||
/// and:
|
||||
///
|
||||
/// unsigned int array[] ={0};
|
||||
///
|
||||
/// In both cases, the size of the ELF symbol of the variable 'array'
|
||||
/// is 32 bits, but, at least in the first case
|
||||
bool
|
||||
is_var_1_dim_unknown_size_array_change(const var_decl_sptr& var1,
|
||||
const var_decl_sptr& var2)
|
||||
{
|
||||
type_base_sptr /*first type*/ft =
|
||||
peel_qualified_or_typedef_type(var1->get_type());
|
||||
type_base_sptr /*second type*/st =
|
||||
peel_qualified_or_typedef_type(var2->get_type());
|
||||
|
||||
array_type_def_sptr /*first array type*/fat = is_array_type(ft);
|
||||
array_type_def_sptr /*second array type*/sat = is_array_type(st);
|
||||
|
||||
// The types of the variables must be arrays.
|
||||
if (!fat || !sat)
|
||||
return false;
|
||||
|
||||
// The arrays must have one dimension and at least one of them must
|
||||
// be of unknown size.
|
||||
if (fat->get_subranges().size() != 1
|
||||
|| sat->get_subranges().size() != 1
|
||||
|| (!fat->is_infinite() && !sat->is_infinite()))
|
||||
return false;
|
||||
|
||||
// The variables must be equal modulo their type.
|
||||
if (!var_equals_modulo_types(*var1, *var2, nullptr))
|
||||
return false;
|
||||
|
||||
// The symbols of the variables must be defined and of the same
|
||||
// non-zero size.
|
||||
if (!var1->get_symbol()
|
||||
|| !var2->get_symbol()
|
||||
|| var1->get_symbol()->get_size() != var2->get_symbol()->get_size())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Test if we are looking at a diff that carries a change of
|
||||
/// variables which types are both one dimension array, with one of
|
||||
/// them being of unknow size and the two variables having the same
|
||||
/// symbol size.
|
||||
///
|
||||
/// This can happen in the case of these two declarations, for instance:
|
||||
///
|
||||
/// unsigned int array[];
|
||||
///
|
||||
/// and:
|
||||
///
|
||||
/// unsigned int array[] ={0};
|
||||
///
|
||||
/// In both cases, the size of the ELF symbol of the variable 'array'
|
||||
/// is 32 bits, but, at least in the first case
|
||||
bool
|
||||
is_var_1_dim_unknown_size_array_change(const diff* diff)
|
||||
{
|
||||
const var_diff* d = is_var_diff(diff);
|
||||
|
||||
if (!d)
|
||||
return false;
|
||||
|
||||
var_decl_sptr f = d->first_var(), s = d->second_var();
|
||||
|
||||
return is_var_1_dim_unknown_size_array_change(f, s);
|
||||
}
|
||||
|
||||
/// Test if a class_diff node has static members added or removed.
|
||||
///
|
||||
/// @param diff the diff node to consider.
|
||||
@@ -696,14 +775,10 @@ class_diff_has_harmless_odr_violation_change(const diff* dif)
|
||||
class_decl_sptr first = d->first_class_decl();
|
||||
class_decl_sptr second = d->second_class_decl();
|
||||
|
||||
if (equals(*first, *second, 0))
|
||||
{
|
||||
class_decl_sptr fc = is_class_type(first->get_canonical_type());
|
||||
class_decl_sptr sc = is_class_type(second->get_canonical_type());
|
||||
|
||||
if (!equals(*fc, *sc, 0))
|
||||
return true;
|
||||
}
|
||||
if (first->get_qualified_name() == second->get_qualified_name()
|
||||
&& first != second
|
||||
&& first->get_corpus() == second->get_corpus())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1564,18 +1639,9 @@ has_var_type_cv_qual_change(const diff* dif)
|
||||
if (!var_dif)
|
||||
return false;
|
||||
|
||||
{
|
||||
// Make sure the variable diff does carry a type change at least
|
||||
change_kind ch_kind = NO_CHANGE_KIND;
|
||||
if (equals(*var_dif->first_var(), *var_dif->second_var(), &ch_kind))
|
||||
return false;
|
||||
|
||||
if (!(ch_kind & LOCAL_TYPE_CHANGE_KIND || ch_kind & SUBTYPE_CHANGE_KIND))
|
||||
return false;
|
||||
}
|
||||
|
||||
diff *type_dif = var_dif->type_diff().get();
|
||||
ABG_ASSERT(type_dif);
|
||||
if (!type_dif)
|
||||
return false;
|
||||
|
||||
return type_diff_has_cv_qual_change_only(type_dif);
|
||||
}
|
||||
@@ -1601,9 +1667,9 @@ has_void_ptr_to_ptr_change(const diff* dif)
|
||||
f = peel_qualified_or_typedef_type(f);
|
||||
s = peel_qualified_or_typedef_type(s);
|
||||
|
||||
if (is_void_pointer_type(f)
|
||||
if (is_void_pointer_type_equivalent(f)
|
||||
&& is_pointer_type(s)
|
||||
&& !is_void_pointer_type(s)
|
||||
&& !is_void_pointer_type_equivalent(s)
|
||||
&& f->get_size_in_bits() == s->get_size_in_bits())
|
||||
return true;
|
||||
}
|
||||
@@ -1615,9 +1681,9 @@ has_void_ptr_to_ptr_change(const diff* dif)
|
||||
f = peel_qualified_or_typedef_type(f);
|
||||
s = peel_qualified_or_typedef_type(s);
|
||||
|
||||
if (is_void_pointer_type(f)
|
||||
if (is_void_pointer_type_equivalent(f)
|
||||
&& is_pointer_type(s)
|
||||
&& !is_void_pointer_type(s)
|
||||
&& !is_void_pointer_type_equivalent(s)
|
||||
&& f->get_size_in_bits() == s->get_size_in_bits())
|
||||
return true;
|
||||
}
|
||||
@@ -1629,9 +1695,9 @@ has_void_ptr_to_ptr_change(const diff* dif)
|
||||
f = peel_qualified_or_typedef_type(f);
|
||||
s = peel_qualified_or_typedef_type(s);
|
||||
|
||||
if (is_void_pointer_type(f)
|
||||
if (is_void_pointer_type_equivalent(f)
|
||||
&& is_pointer_type(s)
|
||||
&& !is_void_pointer_type(s)
|
||||
&& !is_void_pointer_type_equivalent(s)
|
||||
&& f->get_size_in_bits() == s->get_size_in_bits())
|
||||
return true;
|
||||
}
|
||||
@@ -1652,30 +1718,9 @@ has_void_ptr_to_ptr_change(const diff* dif)
|
||||
///
|
||||
/// @return true iff @p dif contains the benign array type size change.
|
||||
static bool
|
||||
has_benign_infinite_array_change(const diff* dif)
|
||||
has_benign_array_of_unknown_size_change(const diff* dif)
|
||||
{
|
||||
if (const var_diff* var_dif = is_var_diff(dif))
|
||||
{
|
||||
if (!var_dif->first_var()->get_symbol()
|
||||
|| var_dif->second_var()->get_symbol())
|
||||
return false;
|
||||
|
||||
if (var_dif->first_var()->get_symbol()->get_size()
|
||||
!= var_dif->second_var()->get_symbol()->get_size())
|
||||
return false;
|
||||
|
||||
const diff *d = var_dif->type_diff().get();
|
||||
if (!d)
|
||||
return false;
|
||||
d = peel_qualified_diff(d);
|
||||
if (const array_diff *a = is_array_diff(d))
|
||||
{
|
||||
array_type_def_sptr f = a->first_array(), s = a->second_array();
|
||||
if (f->is_infinite() != s->is_infinite())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return is_var_1_dim_unknown_size_array_change(dif);
|
||||
}
|
||||
|
||||
/// Test if a union diff node does have changes that don't impact its
|
||||
@@ -1769,7 +1814,7 @@ categorize_harmless_diff_node(diff *d, bool pre)
|
||||
if (has_void_ptr_to_ptr_change(d))
|
||||
category |= VOID_PTR_TO_PTR_CHANGE_CATEGORY;
|
||||
|
||||
if (has_benign_infinite_array_change(d))
|
||||
if (has_benign_array_of_unknown_size_change(d))
|
||||
category |= BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY;
|
||||
|
||||
if (category)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2017-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2017-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -174,11 +174,22 @@ struct diff_context::priv
|
||||
unordered_diff_sptr_set live_diffs_;
|
||||
vector<diff_sptr> canonical_diffs;
|
||||
vector<filtering::filter_base_sptr> filters_;
|
||||
// All the suppressions specifications are stored in this data
|
||||
// member.
|
||||
suppressions_type suppressions_;
|
||||
// The negated suppressions specifications that are in
|
||||
// suppressions_ are stored here. Each time suppressions_ is
|
||||
// modified, this data member should be cleared.
|
||||
suppressions_type negated_suppressions_;
|
||||
// The non-negated suppressions specifications that are in
|
||||
// suppressions_ are stored here. Each time suppressions_ is
|
||||
// modified, this data member should be cleared.
|
||||
suppressions_type direct_suppressions_;
|
||||
pointer_map visited_diff_nodes_;
|
||||
corpus_diff_sptr corpus_diff_;
|
||||
ostream* default_output_stream_;
|
||||
ostream* error_output_stream_;
|
||||
bool perform_change_categorization_;
|
||||
bool leaf_changes_only_;
|
||||
bool forbid_visiting_a_node_twice_;
|
||||
bool reset_visited_diffs_for_each_interface_;
|
||||
@@ -202,12 +213,14 @@ struct diff_context::priv
|
||||
bool show_unreachable_types_;
|
||||
bool show_impacted_interfaces_;
|
||||
bool dump_diff_tree_;
|
||||
bool do_log_;
|
||||
|
||||
priv()
|
||||
: allowed_category_(EVERYTHING_CATEGORY),
|
||||
reporter_(),
|
||||
default_output_stream_(),
|
||||
error_output_stream_(),
|
||||
perform_change_categorization_(true),
|
||||
leaf_changes_only_(),
|
||||
forbid_visiting_a_node_twice_(true),
|
||||
reset_visited_diffs_for_each_interface_(),
|
||||
@@ -230,7 +243,8 @@ struct diff_context::priv
|
||||
show_added_syms_unreferenced_by_di_(true),
|
||||
show_unreachable_types_(false),
|
||||
show_impacted_interfaces_(true),
|
||||
dump_diff_tree_()
|
||||
dump_diff_tree_(),
|
||||
do_log_()
|
||||
{}
|
||||
};// end struct diff_context::priv
|
||||
|
||||
@@ -304,6 +318,13 @@ public:
|
||||
if (ctxt->get_allowed_category() == EVERYTHING_CATEGORY)
|
||||
return false;
|
||||
|
||||
// If this node is on the path of a node that *must* be reported,
|
||||
// then do not filter it.
|
||||
if (category & (HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
|
||||
| HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY
|
||||
| HAS_ALLOWED_CHANGE_CATEGORY))
|
||||
return false;
|
||||
|
||||
/// We don't want to display nodes suppressed by a user-provided
|
||||
/// suppression specification or by a "private type" suppression
|
||||
/// specification.
|
||||
@@ -393,6 +414,17 @@ struct pointer_diff::priv
|
||||
{}
|
||||
};//end struct pointer_diff::priv
|
||||
|
||||
/// The internal type for the impl idiom implementation of @ref
|
||||
/// subrange_diff.
|
||||
struct subrange_diff::priv
|
||||
{
|
||||
diff_sptr underlying_type_diff_;
|
||||
|
||||
priv(diff_sptr u)
|
||||
: underlying_type_diff_(u)
|
||||
{}
|
||||
}; // end struct subrange_diff::priv
|
||||
|
||||
struct array_diff::priv
|
||||
{
|
||||
/// The diff between the two array element types.
|
||||
@@ -1127,6 +1159,9 @@ struct corpus_diff::priv
|
||||
size_t &num_filtered_removed,
|
||||
size_t &num_filtered_changed);
|
||||
|
||||
const string_diff_sptr_map&
|
||||
changed_unreachable_types() const;
|
||||
|
||||
const vector<diff_sptr>&
|
||||
changed_unreachable_types_sorted() const;
|
||||
|
||||
|
||||
+916
-69
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-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
|
||||
|
||||
+75
-27
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2016-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2016-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
///
|
||||
@@ -40,6 +40,12 @@ typedef vector<regex_t_sptr> regex_t_sptrs_type;
|
||||
/// Convenience typedef for a hash map which key is a string and which
|
||||
/// data is a vector of abigail::ir::function_decl*
|
||||
typedef unordered_map<string, vector<function_decl*> > str_fn_ptrs_map_type;
|
||||
|
||||
/// Convenience typedef for a hash map which key is a string and which
|
||||
/// data is a set of abigail::ir::function_decl*
|
||||
typedef unordered_map<string, std::unordered_set<function_decl*> >
|
||||
str_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;
|
||||
@@ -63,7 +69,7 @@ class corpus::exported_decls_builder::priv
|
||||
// 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_ptrs_map_type id_fns_map_;
|
||||
str_fn_ptr_set_map_type id_fns_map_;
|
||||
str_var_ptr_map_type id_var_map_;
|
||||
strings_type& fns_suppress_regexps_;
|
||||
regex_t_sptrs_type compiled_fns_suppress_regexp_;
|
||||
@@ -197,7 +203,7 @@ public:
|
||||
///
|
||||
/// @return a map which key is a string and which data is a pointer
|
||||
/// to a function.
|
||||
const str_fn_ptrs_map_type&
|
||||
const str_fn_ptr_set_map_type&
|
||||
id_fns_map() const
|
||||
{return id_fns_map_;}
|
||||
|
||||
@@ -210,7 +216,7 @@ public:
|
||||
///
|
||||
/// @return a map which key is a string and which data is a pointer
|
||||
/// to a function.
|
||||
str_fn_ptrs_map_type&
|
||||
str_fn_ptr_set_map_type&
|
||||
id_fns_map()
|
||||
{return id_fns_map_;}
|
||||
|
||||
@@ -267,11 +273,11 @@ public:
|
||||
///
|
||||
/// @return the pointer to the vector of functions with ID @p fn_id,
|
||||
/// or nil if no function with that ID exists.
|
||||
vector<function_decl*>*
|
||||
std::unordered_set<function_decl*>*
|
||||
fn_id_is_in_id_fns_map(const string& fn_id)
|
||||
{
|
||||
str_fn_ptrs_map_type& m = id_fns_map();
|
||||
str_fn_ptrs_map_type::iterator i = m.find(fn_id);
|
||||
str_fn_ptr_set_map_type& m = id_fns_map();
|
||||
str_fn_ptr_set_map_type::iterator i = m.find(fn_id);
|
||||
if (i == m.end())
|
||||
return 0;
|
||||
return &i->second;
|
||||
@@ -286,47 +292,87 @@ public:
|
||||
/// @p fn, that are present in the id-functions map, or nil if no
|
||||
/// function with the same ID as @p fn is present in the
|
||||
/// id-functions map.
|
||||
vector<function_decl*>*
|
||||
std::unordered_set<function_decl*>*
|
||||
fn_id_is_in_id_fns_map(const function_decl* fn)
|
||||
{
|
||||
string fn_id = fn->get_id();
|
||||
return fn_id_is_in_id_fns_map(fn_id);
|
||||
}
|
||||
|
||||
/// Test if a given function is present in a vector of functions.
|
||||
/// Test if a given function is present in a set of functions.
|
||||
///
|
||||
/// The function compares the ID and the qualified name of
|
||||
/// functions.
|
||||
///
|
||||
/// @param fn the function to consider.
|
||||
///
|
||||
/// @parm fns the vector of functions to consider.
|
||||
/// @parm fns the set of functions to consider.
|
||||
static bool
|
||||
fn_is_in_fns(const function_decl* fn, const vector<function_decl*>& fns)
|
||||
fn_is_in_fns(function_decl* fn,
|
||||
const std::unordered_set<function_decl*>& fns)
|
||||
{
|
||||
if (fns.empty())
|
||||
return false;
|
||||
|
||||
if (fns.find(fn) != fns.end())
|
||||
return true;
|
||||
|
||||
const string fn_id = fn->get_id();
|
||||
for (vector<function_decl*>::const_iterator i = fns.begin();
|
||||
i != fns.end();
|
||||
++i)
|
||||
if ((*i)->get_id() == fn_id
|
||||
&& (*i)->get_qualified_name() == fn->get_qualified_name())
|
||||
for (const auto f : fns)
|
||||
if (f->get_id() == fn_id
|
||||
&& f->get_qualified_name() == fn->get_qualified_name())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Test if a given function is present in a set of functions,
|
||||
/// by looking at the pretty representation of the function, in
|
||||
/// addition to looking at its ID.
|
||||
///
|
||||
/// This is useful because sometimes a given ELF symbol (alias)
|
||||
/// might be for several different functions. In that case, using
|
||||
/// the function pretty representation might be a way to
|
||||
/// differentiate the functions having the same ELF symbol alias.
|
||||
///
|
||||
/// The function compares the ID and the qualified name of
|
||||
/// functions.
|
||||
///
|
||||
/// @param fn the function to consider.
|
||||
///
|
||||
/// @parm fns the set of functions to consider.
|
||||
///
|
||||
/// @return true if @p fn is present in @p fns.
|
||||
static bool
|
||||
fn_is_in_fns_by_repr(function_decl* fn,
|
||||
const std::unordered_set<function_decl*>& fns,
|
||||
string& pretty_representation)
|
||||
{
|
||||
if (!fn_is_in_fns(fn, fns))
|
||||
return false;
|
||||
|
||||
const string repr = fn->get_pretty_representation();
|
||||
const string fn_id = fn->get_id();
|
||||
for (const auto f : fns)
|
||||
if (f->get_id() == fn_id
|
||||
&& f->get_pretty_representation() == repr)
|
||||
{
|
||||
pretty_representation = repr;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Test if a function is in the id-functions map.
|
||||
///
|
||||
/// @param fn the function to consider.
|
||||
///
|
||||
/// @return true iff the function is in the id-functions map.
|
||||
bool
|
||||
fn_is_in_id_fns_map(const function_decl* fn)
|
||||
fn_is_in_id_fns_map(function_decl* fn)
|
||||
{
|
||||
vector<function_decl*>* fns = fn_id_is_in_id_fns_map(fn);
|
||||
std::unordered_set<function_decl*>* fns = fn_id_is_in_id_fns_map(fn);
|
||||
if (fns && fn_is_in_fns(fn, *fns))
|
||||
return true;
|
||||
return false;
|
||||
@@ -344,10 +390,10 @@ public:
|
||||
|
||||
// First associate the function id to the function.
|
||||
string fn_id = fn->get_id();
|
||||
vector<function_decl*>* fns = fn_id_is_in_id_fns_map(fn_id);
|
||||
std::unordered_set<function_decl*>* fns = fn_id_is_in_id_fns_map(fn_id);
|
||||
if (!fns)
|
||||
fns = &(id_fns_map()[fn_id] = vector<function_decl*>());
|
||||
fns->push_back(fn);
|
||||
fns = &(id_fns_map()[fn_id] = std::unordered_set<function_decl*>());
|
||||
fns->insert(fn);
|
||||
|
||||
// Now associate all aliases of the underlying symbol to the
|
||||
// function too.
|
||||
@@ -361,8 +407,8 @@ public:
|
||||
goto loop;
|
||||
fns = fn_id_is_in_id_fns_map(fn_id);
|
||||
if (!fns)
|
||||
fns = &(id_fns_map()[fn_id] = vector<function_decl*>());
|
||||
fns->push_back(fn);
|
||||
fns = &(id_fns_map()[fn_id] = std::unordered_set<function_decl*>());
|
||||
fns->insert(fn);
|
||||
loop:
|
||||
sym = sym->get_next_alias();
|
||||
}
|
||||
@@ -403,12 +449,12 @@ public:
|
||||
///
|
||||
/// @param fn the function to add to the set of exported functions.
|
||||
void
|
||||
add_fn_to_exported(const function_decl* fn)
|
||||
add_fn_to_exported(function_decl* fn)
|
||||
{
|
||||
if (!fn_is_in_id_fns_map(fn))
|
||||
{
|
||||
fns_.push_back(const_cast<function_decl*>(fn));
|
||||
add_fn_to_id_fns_map(const_cast<function_decl*>(fn));
|
||||
fns_.push_back(fn);
|
||||
add_fn_to_id_fns_map(fn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -701,6 +747,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;
|
||||
|
||||
private:
|
||||
priv();
|
||||
@@ -723,7 +770,8 @@ public:
|
||||
group(),
|
||||
origin_(ARTIFICIAL_ORIGIN),
|
||||
path(p),
|
||||
pub_type_pretty_reprs_()
|
||||
pub_type_pretty_reprs_(),
|
||||
do_log()
|
||||
{}
|
||||
|
||||
type_maps&
|
||||
|
||||
+103
-25
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
|
||||
#include "abg-internal.h"
|
||||
|
||||
@@ -109,6 +110,28 @@ corpus::functions&
|
||||
corpus::exported_decls_builder::exported_functions()
|
||||
{return priv_->fns_;}
|
||||
|
||||
/// Test if a given function ID maps to several functions in the same corpus.
|
||||
///
|
||||
/// The magic of ELF symbol aliases makes it possible for an ELF
|
||||
/// symbol alias to designate several different functions. This
|
||||
/// function tests if the ELF symbol of a given function has a aliases
|
||||
/// that designates another function or not.
|
||||
///
|
||||
/// @param fn the function to consider.
|
||||
///
|
||||
/// @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)
|
||||
{
|
||||
std::unordered_set<function_decl*> *fns_for_id =
|
||||
priv_->fn_id_is_in_id_fns_map(fn);
|
||||
if (fns_for_id && fns_for_id->size() > 1)
|
||||
return fns_for_id;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Getter for the reference to the vector of exported variables.
|
||||
/// This vector is shared with with the @ref corpus. It's where the
|
||||
/// set of exported variable is ultimately stored.
|
||||
@@ -133,7 +156,7 @@ corpus::exported_decls_builder::exported_variables()
|
||||
///
|
||||
/// @param fn the function to add the set of exported functions.
|
||||
void
|
||||
corpus::exported_decls_builder::maybe_add_fn_to_exported_fns(const function_decl* fn)
|
||||
corpus::exported_decls_builder::maybe_add_fn_to_exported_fns(function_decl* fn)
|
||||
{
|
||||
if (!fn->get_is_in_public_symbol_table())
|
||||
return;
|
||||
@@ -313,9 +336,15 @@ corpus::priv::get_sorted_fun_symbols() const
|
||||
{
|
||||
if (!sorted_fun_symbols)
|
||||
{
|
||||
auto filter = symtab_->make_filter();
|
||||
filter.set_functions();
|
||||
sorted_fun_symbols = elf_symbols(symtab_->begin(filter), symtab_->end());
|
||||
if (symtab_)
|
||||
{
|
||||
auto filter = symtab_->make_filter();
|
||||
filter.set_functions();
|
||||
sorted_fun_symbols = elf_symbols(symtab_->begin(filter),
|
||||
symtab_->end());
|
||||
}
|
||||
else
|
||||
sorted_fun_symbols = elf_symbols();
|
||||
}
|
||||
return *sorted_fun_symbols;
|
||||
}
|
||||
@@ -349,13 +378,18 @@ corpus::priv::get_sorted_undefined_fun_symbols() const
|
||||
{
|
||||
if (!sorted_undefined_fun_symbols)
|
||||
{
|
||||
auto filter = symtab_->make_filter();
|
||||
filter.set_functions();
|
||||
filter.set_undefined_symbols();
|
||||
filter.set_public_symbols(false);
|
||||
if (symtab_)
|
||||
{
|
||||
auto filter = symtab_->make_filter();
|
||||
filter.set_functions();
|
||||
filter.set_undefined_symbols();
|
||||
filter.set_public_symbols(false);
|
||||
|
||||
sorted_undefined_fun_symbols =
|
||||
elf_symbols(symtab_->begin(filter), symtab_->end());
|
||||
sorted_undefined_fun_symbols =
|
||||
elf_symbols(symtab_->begin(filter), symtab_->end());
|
||||
}
|
||||
else
|
||||
sorted_undefined_fun_symbols = elf_symbols();
|
||||
}
|
||||
return *sorted_undefined_fun_symbols;
|
||||
}
|
||||
@@ -446,10 +480,16 @@ corpus::priv::get_sorted_var_symbols() const
|
||||
{
|
||||
if (!sorted_var_symbols)
|
||||
{
|
||||
auto filter = symtab_->make_filter();
|
||||
filter.set_variables();
|
||||
if (symtab_)
|
||||
{
|
||||
auto filter = symtab_->make_filter();
|
||||
filter.set_variables();
|
||||
|
||||
sorted_var_symbols = elf_symbols(symtab_->begin(filter), symtab_->end());
|
||||
sorted_var_symbols = elf_symbols(symtab_->begin(filter),
|
||||
symtab_->end());
|
||||
}
|
||||
else
|
||||
sorted_var_symbols = elf_symbols();
|
||||
}
|
||||
return *sorted_var_symbols;
|
||||
}
|
||||
@@ -483,13 +523,18 @@ corpus::priv::get_sorted_undefined_var_symbols() const
|
||||
{
|
||||
if (!sorted_undefined_var_symbols)
|
||||
{
|
||||
auto filter = symtab_->make_filter();
|
||||
filter.set_variables();
|
||||
filter.set_undefined_symbols();
|
||||
filter.set_public_symbols(false);
|
||||
if (symtab_)
|
||||
{
|
||||
auto filter = symtab_->make_filter();
|
||||
filter.set_variables();
|
||||
filter.set_undefined_symbols();
|
||||
filter.set_public_symbols(false);
|
||||
|
||||
sorted_undefined_var_symbols =
|
||||
elf_symbols(symtab_->begin(filter), symtab_->end());
|
||||
sorted_undefined_var_symbols =
|
||||
elf_symbols(symtab_->begin(filter), symtab_->end());
|
||||
}
|
||||
else
|
||||
sorted_undefined_var_symbols = elf_symbols();
|
||||
}
|
||||
return *sorted_undefined_var_symbols;
|
||||
}
|
||||
@@ -611,6 +656,20 @@ const environment&
|
||||
corpus::get_environment() const
|
||||
{return priv_->env;}
|
||||
|
||||
/// Test if logging was requested.
|
||||
///
|
||||
/// @return true iff logging was requested.
|
||||
bool
|
||||
corpus::do_log() const
|
||||
{return priv_->do_log;}
|
||||
|
||||
/// Request logging, or not.
|
||||
///
|
||||
/// @param f true iff logging is requested.
|
||||
void
|
||||
corpus::do_log(bool f)
|
||||
{priv_->do_log = f;}
|
||||
|
||||
/// Add a translation unit to the current ABI Corpus.
|
||||
///
|
||||
/// Note that two translation units with the same path (as returned by
|
||||
@@ -715,7 +774,7 @@ corpus::recording_types_reachable_from_public_interface_supported()
|
||||
void
|
||||
corpus::record_type_as_reachable_from_public_interfaces(const type_base& t)
|
||||
{
|
||||
string repr = get_pretty_representation(&t, /*internal=*/true);
|
||||
string repr = get_pretty_representation(&t, /*internal=*/false);
|
||||
interned_string s = t.get_environment().intern(repr);
|
||||
priv_->get_public_types_pretty_representations()->insert(s);
|
||||
}
|
||||
@@ -733,7 +792,7 @@ corpus::record_type_as_reachable_from_public_interfaces(const type_base& t)
|
||||
bool
|
||||
corpus::type_is_reachable_from_public_interfaces(const type_base& t) const
|
||||
{
|
||||
string repr = get_pretty_representation(&t, /*internal=*/true);
|
||||
string repr = get_pretty_representation(&t, /*internal=*/false);
|
||||
interned_string s = t.get_environment().intern(repr);
|
||||
|
||||
return (priv_->get_public_types_pretty_representations()->find(s)
|
||||
@@ -1278,12 +1337,11 @@ corpus::get_functions() const
|
||||
///
|
||||
/// @return the vector functions which ID is @p id, or nil if no
|
||||
/// function with that ID was found.
|
||||
const vector<function_decl*>*
|
||||
const std::unordered_set<function_decl*>*
|
||||
corpus::lookup_functions(const string& id) const
|
||||
{
|
||||
exported_decls_builder_sptr b = get_exported_decls_builder();
|
||||
str_fn_ptrs_map_type::const_iterator i =
|
||||
b->priv_->id_fns_map_.find(id);
|
||||
auto i = b->priv_->id_fns_map_.find(id);
|
||||
if (i == b->priv_->id_fns_map_.end())
|
||||
return 0;
|
||||
return &i->second;
|
||||
@@ -1597,6 +1655,7 @@ operator&=(corpus::origin &l, corpus::origin r)
|
||||
/// Type of the private data of @ref corpus_group
|
||||
struct corpus_group::priv
|
||||
{
|
||||
std::set<string> corpora_paths;
|
||||
corpora_type corpora;
|
||||
istring_function_decl_ptr_map_type fns_map;
|
||||
vector<function_decl*> fns;
|
||||
@@ -1686,6 +1745,10 @@ corpus_group::add_corpus(const corpus_sptr& corp)
|
||||
if (!corp)
|
||||
return;
|
||||
|
||||
if (!corp->get_path().empty()
|
||||
&& has_corpus(corp->get_path()))
|
||||
return;
|
||||
|
||||
// Ensure the new architecture name matches the current one.
|
||||
string cur_arch = get_architecture_name(),
|
||||
corp_arch = corp->get_architecture_name();
|
||||
@@ -1701,6 +1764,7 @@ corpus_group::add_corpus(const corpus_sptr& corp)
|
||||
|
||||
priv_->corpora.push_back(corp);
|
||||
corp->set_group(this);
|
||||
priv_->corpora_paths.insert(corp->get_path());
|
||||
|
||||
/// Add the unreferenced function and variable symbols of this
|
||||
/// corpus to the unreferenced symbols of the current corpus group.
|
||||
@@ -1708,6 +1772,20 @@ corpus_group::add_corpus(const corpus_sptr& corp)
|
||||
priv_->add_unref_var_symbols(get_unreferenced_variable_symbols());
|
||||
}
|
||||
|
||||
/// Test if a corpus of a given path has been added to the group.
|
||||
///
|
||||
/// @param path the path to the corpus to consider.
|
||||
///
|
||||
/// @return true iff a corpus with path @p path is already present in
|
||||
/// the group⋅
|
||||
bool
|
||||
corpus_group::has_corpus(const string& path)
|
||||
{
|
||||
if (priv_->corpora_paths.find(path) != priv_->corpora_paths.end())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Getter of the vector of corpora held by the current @ref
|
||||
/// corpus_group.
|
||||
///
|
||||
|
||||
+88
-31
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2021-2022 Oracle, Inc.
|
||||
// Copyright (C) 2021-2023 Oracle, Inc.
|
||||
//
|
||||
// Author: Jose E. Marchesi
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <fcntl.h> /* For open(3) */
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
@@ -61,7 +62,15 @@ process_ctf_base_type(reader *rdr,
|
||||
|
||||
static decl_base_sptr
|
||||
build_ir_node_for_variadic_parameter_type(reader &rdr,
|
||||
translation_unit_sptr tunit);
|
||||
const translation_unit_sptr& tunit);
|
||||
|
||||
static decl_base_sptr
|
||||
build_ir_node_for_void_type(reader& rdr,
|
||||
const translation_unit_sptr& tunit);
|
||||
|
||||
static type_or_decl_base_sptr
|
||||
build_ir_node_for_void_pointer_type(reader& rdr,
|
||||
const translation_unit_sptr& tunit);
|
||||
|
||||
static function_type_sptr
|
||||
process_ctf_function_type(reader *rdr,
|
||||
@@ -131,7 +140,7 @@ class reader : public elf_based_reader
|
||||
|
||||
/// A map associating CTF type ids with libabigail IR types. This
|
||||
/// is used to reuse already generated types.
|
||||
unordered_map<string,type_base_sptr> types_map;
|
||||
string_type_base_sptr_map_type types_map;
|
||||
|
||||
/// A set associating unknown CTF type ids
|
||||
std::set<ctf_id_t> unknown_types_set;
|
||||
@@ -203,8 +212,10 @@ public:
|
||||
void
|
||||
canonicalize_all_types(void)
|
||||
{
|
||||
for (auto t = types_map.begin(); t != types_map.end(); t++)
|
||||
canonicalize (t->second);
|
||||
canonicalize_types
|
||||
(types_map.begin(), types_map.end(),
|
||||
[](const string_type_base_sptr_map_type::const_iterator& i)
|
||||
{return i->second;});
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
@@ -277,7 +288,7 @@ public:
|
||||
{
|
||||
load_all_types = load_all_types;
|
||||
linux_kernel_mode = linux_kernel_mode;
|
||||
reset(elf_path, debug_info_root_paths);
|
||||
elf_based_reader::initialize(elf_path, debug_info_root_paths);
|
||||
}
|
||||
|
||||
/// Setter of the current translation unit.
|
||||
@@ -334,12 +345,8 @@ public:
|
||||
// for vmlinux.ctfa should be provided with --debug-info-dir
|
||||
// option.
|
||||
for (const auto& path : debug_info_root_paths())
|
||||
{
|
||||
ctfa_dirname = *path;
|
||||
ctfa_file = ctfa_dirname + "/vmlinux.ctfa";
|
||||
if (file_exists(ctfa_file))
|
||||
return true;
|
||||
}
|
||||
if (tools_utils::find_file_under_dir(*path, "vmlinux.ctfa", ctfa_file))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -426,10 +433,10 @@ public:
|
||||
&& corpus_group())
|
||||
{
|
||||
tools_utils::base_name(corpus_path(), dict_name);
|
||||
|
||||
if (dict_name != "vmlinux")
|
||||
// remove .ko suffix
|
||||
dict_name.erase(dict_name.length() - 3, 3);
|
||||
// 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(), '-', '_');
|
||||
}
|
||||
@@ -729,7 +736,7 @@ process_ctf_typedef(reader *rdr,
|
||||
|
||||
const char *typedef_name = ctf_type_name_raw(ctf_dictionary, ctf_type);
|
||||
if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
|
||||
if (result = lookup_typedef_type(typedef_name, *corp))
|
||||
if ((result = lookup_typedef_type(typedef_name, *corp)))
|
||||
return result;
|
||||
|
||||
type_base_sptr utype = rdr->build_type(ctf_dictionary, ctf_utype);
|
||||
@@ -801,8 +808,9 @@ process_ctf_base_type(reader *rdr,
|
||||
&& type_encoding.cte_format == CTF_INT_SIGNED)
|
||||
{
|
||||
/* This is the `void' type. */
|
||||
type_base_sptr void_type = rdr->env().get_void_type();
|
||||
decl_base_sptr type_declaration = get_type_declaration(void_type);
|
||||
decl_base_sptr type_declaration = build_ir_node_for_void_type(*rdr,
|
||||
tunit);
|
||||
type_base_sptr void_type = is_type(type_declaration);
|
||||
result = is_type_decl(type_declaration);
|
||||
canonicalize(result);
|
||||
}
|
||||
@@ -814,7 +822,7 @@ process_ctf_base_type(reader *rdr,
|
||||
integral_type int_type;
|
||||
if (parse_integral_type(type_name, int_type))
|
||||
normalized_type_name = int_type.to_string();
|
||||
if (result = lookup_basic_type(normalized_type_name, *corp))
|
||||
if ((result = lookup_basic_type(normalized_type_name, *corp)))
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -842,21 +850,65 @@ process_ctf_base_type(reader *rdr,
|
||||
///
|
||||
/// @param rdr the read context to use.
|
||||
///
|
||||
/// @param tunit the translation unit it should belong to.
|
||||
///
|
||||
/// @return the variadic parameter type.
|
||||
static decl_base_sptr
|
||||
build_ir_node_for_variadic_parameter_type(reader &rdr,
|
||||
translation_unit_sptr tunit)
|
||||
const translation_unit_sptr& tunit)
|
||||
{
|
||||
|
||||
const ir::environment& env = rdr.env();
|
||||
type_base_sptr t = env.get_variadic_parameter_type();
|
||||
decl_base_sptr type_declaration = get_type_declaration(t);
|
||||
if (!has_scope(type_declaration))
|
||||
add_decl_to_scope(type_declaration, tunit->get_global_scope());
|
||||
add_decl_to_scope(type_declaration, tunit->get_global_scope());
|
||||
canonicalize(t);
|
||||
return type_declaration;
|
||||
}
|
||||
|
||||
/// Build the IR node for a void type.
|
||||
///
|
||||
/// Note that this returns the unique pointer
|
||||
/// environment::get_void_type(), which is added to the current
|
||||
/// translation unit if it's the first it's being used.
|
||||
///
|
||||
/// @param rdr the read context to use.
|
||||
///
|
||||
/// @param tunit the translation unit it should belong to.
|
||||
///
|
||||
/// @return the void type type.
|
||||
static decl_base_sptr
|
||||
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);
|
||||
return is_decl(t);
|
||||
}
|
||||
|
||||
/// Build the IR node for a void pointer type.
|
||||
///
|
||||
/// Note that this returns the unique pointer
|
||||
/// environment::get_void_pointer_type(), which is added to the
|
||||
/// current translation unit if it's the first it's being used.
|
||||
///
|
||||
/// @param rdr the read context to use.
|
||||
///
|
||||
/// @param tunit the translation unit it should belong to.
|
||||
///
|
||||
/// @return the void pointer type.
|
||||
static type_or_decl_base_sptr
|
||||
build_ir_node_for_void_pointer_type(reader& rdr,
|
||||
const translation_unit_sptr& tunit)
|
||||
{
|
||||
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);
|
||||
return is_decl(t);
|
||||
}
|
||||
|
||||
/// Build and return a function type libabigail IR.
|
||||
///
|
||||
/// @param rdr the read context.
|
||||
@@ -1036,7 +1088,7 @@ process_ctf_forward_type(reader *rdr,
|
||||
{
|
||||
if (!type_is_anonymous)
|
||||
if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
|
||||
if (result = lookup_class_type(type_name, *corp))
|
||||
if ((result = lookup_class_type(type_name, *corp)))
|
||||
return is_type(result);
|
||||
|
||||
class_decl_sptr
|
||||
@@ -1081,7 +1133,7 @@ process_ctf_struct_type(reader *rdr,
|
||||
|
||||
if (!struct_type_is_anonymous)
|
||||
if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
|
||||
if (result = lookup_class_type(struct_type_name, *corp))
|
||||
if ((result = lookup_class_type(struct_type_name, *corp)))
|
||||
return result;
|
||||
|
||||
/* The libabigail IR encodes C struct types in `class' IR nodes. */
|
||||
@@ -1134,7 +1186,7 @@ process_ctf_union_type(reader *rdr,
|
||||
|
||||
if (!union_type_is_anonymous)
|
||||
if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
|
||||
if (result = lookup_union_type(union_type_name, *corp))
|
||||
if ((result = lookup_union_type(union_type_name, *corp)))
|
||||
return result;
|
||||
|
||||
/* Create the corresponding libabigail union IR node. */
|
||||
@@ -1440,10 +1492,15 @@ process_ctf_pointer_type(reader *rdr,
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result.reset(new pointer_type_def(target_type,
|
||||
ctf_type_size(ctf_dictionary, ctf_type) * 8,
|
||||
ctf_type_align(ctf_dictionary, ctf_type) * 8,
|
||||
location()));
|
||||
if (rdr->env().is_void_type(target_type))
|
||||
result = is_pointer_type(build_ir_node_for_void_pointer_type(*rdr, tunit));
|
||||
else
|
||||
result.reset(new pointer_type_def(target_type,
|
||||
ctf_type_size(ctf_dictionary,
|
||||
ctf_type) * 8,
|
||||
ctf_type_align(ctf_dictionary,
|
||||
ctf_type) * 8,
|
||||
location()));
|
||||
if (result)
|
||||
{
|
||||
add_decl_to_scope(result, tunit->get_global_scope());
|
||||
@@ -1475,7 +1532,7 @@ process_ctf_enum_type(reader *rdr,
|
||||
|
||||
if (!enum_name.empty())
|
||||
if (corpus_sptr corp = rdr->should_reuse_type_from_corpus_group())
|
||||
if (result = lookup_enum_type(enum_name, *corp))
|
||||
if ((result = lookup_enum_type(enum_name, *corp)))
|
||||
return result;
|
||||
|
||||
/* Build a signed integral type for the type of the enumerators, aka
|
||||
|
||||
+259
-196
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2017-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2017-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -162,7 +162,9 @@ default_reporter::report(const enum_diff& d, ostream& out,
|
||||
{
|
||||
out << indent
|
||||
<< " '"
|
||||
<< i->get_qualified_name()
|
||||
<< (first->get_is_anonymous()
|
||||
? i->get_name()
|
||||
: i->get_qualified_name())
|
||||
<< "' value '"
|
||||
<< i->get_value()
|
||||
<< "'";
|
||||
@@ -181,7 +183,9 @@ default_reporter::report(const enum_diff& d, ostream& out,
|
||||
{
|
||||
out << indent
|
||||
<< " '"
|
||||
<< i->get_qualified_name()
|
||||
<< (second->get_is_anonymous()
|
||||
? i->get_name()
|
||||
:i->get_qualified_name())
|
||||
<< "' value '"
|
||||
<< i->get_value()
|
||||
<< "'";
|
||||
@@ -201,7 +205,9 @@ default_reporter::report(const enum_diff& d, ostream& out,
|
||||
{
|
||||
out << indent
|
||||
<< " '"
|
||||
<< i->first.get_qualified_name()
|
||||
<< (first->get_is_anonymous()
|
||||
? i->first.get_name()
|
||||
: i->first.get_qualified_name())
|
||||
<< "' from value '"
|
||||
<< i->first.get_value() << "' to '"
|
||||
<< i->second.get_value() << "'";
|
||||
@@ -272,7 +278,8 @@ default_reporter::report(const typedef_diff& d,
|
||||
|
||||
typedef_decl_sptr f = d.first_typedef_decl(), s = d.second_typedef_decl();
|
||||
|
||||
report_non_type_typedef_changes(d, out, indent);
|
||||
if (!d.is_filtered_out_without_looking_at_allowed_changes())
|
||||
report_non_type_typedef_changes(d, out, indent);
|
||||
|
||||
diff_sptr dif = d.underlying_type_diff();
|
||||
if (dif && dif->has_changes())
|
||||
@@ -347,6 +354,38 @@ default_reporter::report_local_qualified_type_changes(const qualified_type_diff&
|
||||
return false;
|
||||
}
|
||||
|
||||
/// For a @ref qualified_type_diff node, report the changes of its
|
||||
/// underlying type.
|
||||
///
|
||||
/// @param d the @ref qualified_type_diff node to consider.
|
||||
///
|
||||
/// @param out the output stream to emit the report to.
|
||||
///
|
||||
/// @param indent the white string to use for indentation.
|
||||
///
|
||||
/// @return true iff a local change has been emitted. In this case,
|
||||
/// the local change is a name change.
|
||||
void
|
||||
default_reporter::report_underlying_changes_of_qualified_type
|
||||
(const qualified_type_diff& d, ostream& out, const string& indent) const
|
||||
{
|
||||
if (!d.to_be_reported())
|
||||
return;
|
||||
|
||||
diff_sptr dif = d.leaf_underlying_type_diff();
|
||||
ABG_ASSERT(dif);
|
||||
ABG_ASSERT(dif->to_be_reported());
|
||||
RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(dif,
|
||||
"unqualified "
|
||||
"underlying type");
|
||||
|
||||
string fltname = dif->first_subject()->get_pretty_representation();
|
||||
out << indent << "in unqualified underlying type '" << fltname << "'";
|
||||
report_loc_info(dif->second_subject(), *d.context(), out);
|
||||
out << ":\n";
|
||||
dif->report(out, indent + " ");
|
||||
}
|
||||
|
||||
/// Report a @ref qualified_type_diff in a serialized form.
|
||||
///
|
||||
/// @param d the @ref qualified_type_diff node to consider.
|
||||
@@ -364,24 +403,14 @@ default_reporter::report(const qualified_type_diff& d, ostream& out,
|
||||
RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(d.first_qualified_type(),
|
||||
d.second_qualified_type());
|
||||
|
||||
if (report_local_qualified_type_changes(d, out, indent))
|
||||
// The local change was emitted and it's a name change. If the
|
||||
// type name changed, the it means the type changed altogether.
|
||||
// It makes a little sense to detail the changes in extenso here.
|
||||
return;
|
||||
if (!d.is_filtered_out_without_looking_at_allowed_changes())
|
||||
if (report_local_qualified_type_changes(d, out, indent))
|
||||
// The local change was emitted and it's a name change. If the
|
||||
// type name changed, the it means the type changed altogether.
|
||||
// It makes a little sense to detail the changes in extenso here.
|
||||
return;
|
||||
|
||||
diff_sptr dif = d.leaf_underlying_type_diff();
|
||||
ABG_ASSERT(dif);
|
||||
ABG_ASSERT(dif->to_be_reported());
|
||||
RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(dif,
|
||||
"unqualified "
|
||||
"underlying type");
|
||||
|
||||
string fltname = dif->first_subject()->get_pretty_representation();
|
||||
out << indent << "in unqualified underlying type '" << fltname << "'";
|
||||
report_loc_info(dif->second_subject(), *d.context(), out);
|
||||
out << ":\n";
|
||||
dif->report(out, indent + " ");
|
||||
report_underlying_changes_of_qualified_type(d, out, indent);
|
||||
}
|
||||
|
||||
/// Report the @ref pointer_diff in a serialized form.
|
||||
@@ -474,8 +503,9 @@ default_reporter::report(const reference_diff& d, ostream& out,
|
||||
enum change_kind k = ir::NO_CHANGE_KIND;
|
||||
equals(*d.first_reference(), *d.second_reference(), &k);
|
||||
|
||||
if ((k & ALL_LOCAL_CHANGES_MASK) && !(k & SUBTYPE_CHANGE_KIND))
|
||||
report_local_reference_type_changes(d, out, indent);
|
||||
if (!d.is_filtered_out_without_looking_at_allowed_changes())
|
||||
if ((k & ALL_LOCAL_CHANGES_MASK) && !(k & SUBTYPE_CHANGE_KIND))
|
||||
report_local_reference_type_changes(d, out, indent);
|
||||
|
||||
if (k & SUBTYPE_CHANGE_KIND)
|
||||
if (diff_sptr dif = d.underlying_type_diff())
|
||||
@@ -503,6 +533,9 @@ void
|
||||
default_reporter::report(const fn_parm_diff& d, ostream& out,
|
||||
const string& indent) const
|
||||
{
|
||||
if (!d.to_be_reported())
|
||||
return;
|
||||
|
||||
function_decl::parameter_sptr f = d.first_parameter(),
|
||||
s = d.second_parameter();
|
||||
|
||||
@@ -514,26 +547,23 @@ default_reporter::report(const fn_parm_diff& d, ostream& out,
|
||||
type_has_sub_type_changes(d.first_parameter()->get_type(),
|
||||
d.second_parameter()->get_type());
|
||||
|
||||
if (d.to_be_reported())
|
||||
{
|
||||
diff_sptr type_diff = d.type_diff();
|
||||
ABG_ASSERT(type_diff->has_changes());
|
||||
diff_sptr type_diff = d.type_diff();
|
||||
ABG_ASSERT(type_diff->has_changes());
|
||||
|
||||
out << indent;
|
||||
if (f->get_is_artificial())
|
||||
out << "implicit ";
|
||||
out << "parameter " << f->get_index();
|
||||
report_loc_info(f, *d.context(), out);
|
||||
out << " of type '"
|
||||
<< f->get_type_pretty_representation();
|
||||
out << indent;
|
||||
if (f->get_is_artificial())
|
||||
out << "implicit ";
|
||||
out << "parameter " << f->get_index();
|
||||
report_loc_info(f, *d.context(), out);
|
||||
out << " of type '"
|
||||
<< f->get_type_pretty_representation();
|
||||
|
||||
if (has_sub_type_change)
|
||||
out << "' has sub-type changes:\n";
|
||||
else
|
||||
out << "' changed:\n";
|
||||
if (has_sub_type_change)
|
||||
out << "' has sub-type changes:\n";
|
||||
else
|
||||
out << "' changed:\n";
|
||||
|
||||
type_diff->report(out, indent + " ");
|
||||
}
|
||||
type_diff->report(out, indent + " ");
|
||||
}
|
||||
|
||||
/// For a @ref function_type_diff node, report the local changes
|
||||
@@ -645,8 +675,30 @@ default_reporter::report(const function_type_diff& d, ostream& out,
|
||||
dif->report(out, indent);
|
||||
}
|
||||
|
||||
report_local_function_type_changes(d, out, indent);
|
||||
if (!d.is_filtered_out_without_looking_at_allowed_changes())
|
||||
report_local_function_type_changes(d, out, indent);
|
||||
}
|
||||
|
||||
/// Report about the change carried by a @ref subrange_diff diff node
|
||||
/// in a serialized form.
|
||||
///
|
||||
/// @param d the diff node to consider.
|
||||
///
|
||||
/// @param out the output stream to report to.
|
||||
///
|
||||
/// @param indent the indentation string to use in the report.
|
||||
void
|
||||
default_reporter::report(const subrange_diff& d, std::ostream& out,
|
||||
const std::string& indent) const
|
||||
{
|
||||
if (!diff_to_be_reported(&d))
|
||||
return;
|
||||
|
||||
RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3(d.first_subrange(),
|
||||
d.second_subrange(),
|
||||
"range type");
|
||||
|
||||
represent(d, d.context(), out,indent, /*local_only=*/false);
|
||||
}
|
||||
|
||||
/// Report a @ref array_diff in a serialized form.
|
||||
@@ -678,10 +730,11 @@ default_reporter::report(const array_diff& d, ostream& out,
|
||||
dif->report(out, indent + " ");
|
||||
}
|
||||
|
||||
report_name_size_and_alignment_changes(d.first_array(),
|
||||
d.second_array(),
|
||||
d.context(),
|
||||
out, indent);
|
||||
if (!d.is_filtered_out_without_looking_at_allowed_changes())
|
||||
report_name_size_and_alignment_changes(d.first_array(),
|
||||
d.second_array(),
|
||||
d.context(),
|
||||
out, indent);
|
||||
}
|
||||
|
||||
/// Generates a report for an intance of @ref base_diff.
|
||||
@@ -702,30 +755,32 @@ default_reporter::report(const base_diff& d, ostream& out,
|
||||
string repr = f->get_base_class()->get_pretty_representation();
|
||||
bool emitted = false;
|
||||
|
||||
if (f->get_is_static() != s->get_is_static())
|
||||
if (!d.is_filtered_out_without_looking_at_allowed_changes())
|
||||
{
|
||||
if (f->get_is_static())
|
||||
out << indent << "is no more static";
|
||||
else
|
||||
out << indent << "now becomes static";
|
||||
emitted = true;
|
||||
if (f->get_is_static() != s->get_is_static())
|
||||
{
|
||||
if (f->get_is_static())
|
||||
out << indent << "is no more static";
|
||||
else
|
||||
out << indent << "now becomes static";
|
||||
emitted = true;
|
||||
}
|
||||
|
||||
if ((d.context()->get_allowed_category() & ACCESS_CHANGE_CATEGORY)
|
||||
&& (f->get_access_specifier() != s->get_access_specifier()))
|
||||
{
|
||||
if (emitted)
|
||||
out << ", ";
|
||||
|
||||
out << "has access changed from '"
|
||||
<< f->get_access_specifier()
|
||||
<< "' to '"
|
||||
<< s->get_access_specifier()
|
||||
<< "'";
|
||||
|
||||
emitted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((d.context()->get_allowed_category() & ACCESS_CHANGE_CATEGORY)
|
||||
&& (f->get_access_specifier() != s->get_access_specifier()))
|
||||
{
|
||||
if (emitted)
|
||||
out << ", ";
|
||||
|
||||
out << "has access changed from '"
|
||||
<< f->get_access_specifier()
|
||||
<< "' to '"
|
||||
<< s->get_access_specifier()
|
||||
<< "'";
|
||||
|
||||
emitted = true;
|
||||
}
|
||||
|
||||
if (class_diff_sptr dif = d.get_underlying_class_diff())
|
||||
{
|
||||
if (dif->to_be_reported())
|
||||
@@ -1493,135 +1548,138 @@ default_reporter::report(const function_decl_diff& d, ostream& out,
|
||||
linkage_names2 =
|
||||
s2->get_aliases_id_string(sc->get_fun_symbol_map());
|
||||
|
||||
/// If the set of linkage names of the function have changed, report
|
||||
/// it.
|
||||
if (linkage_names1 != linkage_names2)
|
||||
if (!d.is_filtered_out_without_looking_at_allowed_changes())
|
||||
{
|
||||
if (linkage_names1.empty())
|
||||
/// If the set of linkage names of the function have changed, report
|
||||
/// it.
|
||||
if (linkage_names1 != linkage_names2)
|
||||
{
|
||||
out << indent << ff->get_pretty_representation()
|
||||
<< " didn't have any linkage name, and it now has: '"
|
||||
<< linkage_names2 << "'\n";
|
||||
}
|
||||
else if (linkage_names2.empty())
|
||||
{
|
||||
out << indent << ff->get_pretty_representation()
|
||||
<< " did have linkage names '" << linkage_names1
|
||||
<< "'\n"
|
||||
<< indent << "but it doesn't have any linkage name anymore\n";
|
||||
}
|
||||
else
|
||||
out << indent << "linkage names of "
|
||||
<< ff->get_pretty_representation()
|
||||
<< "\n" << indent << "changed from '"
|
||||
<< linkage_names1 << "' to '" << linkage_names2 << "'\n";
|
||||
}
|
||||
|
||||
if (qn1 != qn2
|
||||
&& d.type_diff()
|
||||
&& d.type_diff()->to_be_reported())
|
||||
{
|
||||
// So the function has sub-type changes that are to be
|
||||
// reported. Let's see if the function name changed too; if it
|
||||
// did, then we'd report that change right before reporting the
|
||||
// sub-type changes.
|
||||
string frep1 = d.first_function_decl()->get_pretty_representation(),
|
||||
frep2 = d.second_function_decl()->get_pretty_representation();
|
||||
out << indent << "'" << frep1 << " {" << linkage_names1<< "}"
|
||||
<< "' now becomes '"
|
||||
<< frep2 << " {" << linkage_names2 << "}" << "'\n";
|
||||
}
|
||||
|
||||
maybe_report_diff_for_symbol(ff->get_symbol(),
|
||||
sf->get_symbol(),
|
||||
d.context(), out, indent);
|
||||
|
||||
// Now report about inline-ness changes
|
||||
if (ff->is_declared_inline() != sf->is_declared_inline())
|
||||
{
|
||||
out << indent;
|
||||
if (ff->is_declared_inline())
|
||||
out << sf->get_pretty_representation()
|
||||
<< " is not declared inline anymore\n";
|
||||
else
|
||||
out << sf->get_pretty_representation()
|
||||
<< " is now declared inline\n";
|
||||
}
|
||||
|
||||
// Report about vtable offset changes.
|
||||
if (is_member_function(ff) && is_member_function(sf))
|
||||
{
|
||||
bool ff_is_virtual = get_member_function_is_virtual(ff),
|
||||
sf_is_virtual = get_member_function_is_virtual(sf);
|
||||
if (ff_is_virtual != sf_is_virtual)
|
||||
{
|
||||
out << indent;
|
||||
if (ff_is_virtual)
|
||||
out << ff->get_pretty_representation()
|
||||
<< " is no more declared virtual\n";
|
||||
else
|
||||
out << ff->get_pretty_representation()
|
||||
<< " is now declared virtual\n";
|
||||
}
|
||||
|
||||
size_t ff_vtable_offset = get_member_function_vtable_offset(ff),
|
||||
sf_vtable_offset = get_member_function_vtable_offset(sf);
|
||||
if (ff_is_virtual && sf_is_virtual
|
||||
&& (ff_vtable_offset != sf_vtable_offset))
|
||||
{
|
||||
out << indent
|
||||
<< "the vtable offset of " << ff->get_pretty_representation()
|
||||
<< " changed from " << ff_vtable_offset
|
||||
<< " to " << sf_vtable_offset << "\n";
|
||||
}
|
||||
|
||||
// the parent types (classe or union) of the two member
|
||||
// functions.
|
||||
class_or_union_sptr f =
|
||||
is_class_or_union_type(is_method_type(ff->get_type())->get_class_type());
|
||||
class_or_union_sptr s =
|
||||
is_class_or_union_type(is_method_type(sf->get_type())->get_class_type());
|
||||
|
||||
class_decl_sptr fc = is_class_type(f);
|
||||
class_decl_sptr sc = is_class_type(s);
|
||||
|
||||
// Detect if the virtual member function changes above
|
||||
// introduced a vtable change or not.
|
||||
bool vtable_added = false, vtable_removed = false;
|
||||
if (!f->get_is_declaration_only() && !s->get_is_declaration_only())
|
||||
{
|
||||
if (fc && sc)
|
||||
if (linkage_names1.empty())
|
||||
{
|
||||
vtable_added = !fc->has_vtable() && sc->has_vtable();
|
||||
vtable_removed = fc->has_vtable() && !sc->has_vtable();
|
||||
out << indent << ff->get_pretty_representation()
|
||||
<< " didn't have any linkage name, and it now has: '"
|
||||
<< linkage_names2 << "'\n";
|
||||
}
|
||||
else if (linkage_names2.empty())
|
||||
{
|
||||
out << indent << ff->get_pretty_representation()
|
||||
<< " did have linkage names '" << linkage_names1
|
||||
<< "'\n"
|
||||
<< indent << "but it doesn't have any linkage name anymore\n";
|
||||
}
|
||||
else
|
||||
out << indent << "linkage names of "
|
||||
<< ff->get_pretty_representation()
|
||||
<< "\n" << indent << "changed from '"
|
||||
<< linkage_names1 << "' to '" << linkage_names2 << "'\n";
|
||||
}
|
||||
bool vtable_changed = ((ff_is_virtual != sf_is_virtual)
|
||||
|| (ff_vtable_offset != sf_vtable_offset));
|
||||
bool incompatible_change = (ff_vtable_offset != sf_vtable_offset);
|
||||
|
||||
if (vtable_added)
|
||||
out << indent
|
||||
<< " note that a vtable was added to "
|
||||
<< fc->get_pretty_representation()
|
||||
<< "\n";
|
||||
else if (vtable_removed)
|
||||
out << indent
|
||||
<< " note that the vtable was removed from "
|
||||
<< fc->get_pretty_representation()
|
||||
<< "\n";
|
||||
else if (vtable_changed)
|
||||
if (qn1 != qn2
|
||||
&& d.type_diff()
|
||||
&& d.type_diff()->to_be_reported())
|
||||
{
|
||||
// So the function has sub-type changes that are to be
|
||||
// reported. Let's see if the function name changed too; if it
|
||||
// did, then we'd report that change right before reporting the
|
||||
// sub-type changes.
|
||||
string frep1 = d.first_function_decl()->get_pretty_representation(),
|
||||
frep2 = d.second_function_decl()->get_pretty_representation();
|
||||
out << indent << "'" << frep1 << " {" << linkage_names1<< "}"
|
||||
<< "' now becomes '"
|
||||
<< frep2 << " {" << linkage_names2 << "}" << "'\n";
|
||||
}
|
||||
|
||||
maybe_report_diff_for_symbol(ff->get_symbol(),
|
||||
sf->get_symbol(),
|
||||
d.context(), out, indent);
|
||||
|
||||
// Now report about inline-ness changes
|
||||
if (ff->is_declared_inline() != sf->is_declared_inline())
|
||||
{
|
||||
out << indent;
|
||||
if (incompatible_change)
|
||||
out << " note that this is an ABI incompatible "
|
||||
"change to the vtable of ";
|
||||
if (ff->is_declared_inline())
|
||||
out << sf->get_pretty_representation()
|
||||
<< " is not declared inline anymore\n";
|
||||
else
|
||||
out << " note that this induces a change to the vtable of ";
|
||||
out << fc->get_pretty_representation()
|
||||
<< "\n";
|
||||
out << sf->get_pretty_representation()
|
||||
<< " is now declared inline\n";
|
||||
}
|
||||
|
||||
// Report about vtable offset changes.
|
||||
if (is_member_function(ff) && is_member_function(sf))
|
||||
{
|
||||
bool ff_is_virtual = get_member_function_is_virtual(ff),
|
||||
sf_is_virtual = get_member_function_is_virtual(sf);
|
||||
if (ff_is_virtual != sf_is_virtual)
|
||||
{
|
||||
out << indent;
|
||||
if (ff_is_virtual)
|
||||
out << ff->get_pretty_representation()
|
||||
<< " is no more declared virtual\n";
|
||||
else
|
||||
out << ff->get_pretty_representation()
|
||||
<< " is now declared virtual\n";
|
||||
}
|
||||
|
||||
size_t ff_vtable_offset = get_member_function_vtable_offset(ff),
|
||||
sf_vtable_offset = get_member_function_vtable_offset(sf);
|
||||
if (ff_is_virtual && sf_is_virtual
|
||||
&& (ff_vtable_offset != sf_vtable_offset))
|
||||
{
|
||||
out << indent
|
||||
<< "the vtable offset of " << ff->get_pretty_representation()
|
||||
<< " changed from " << ff_vtable_offset
|
||||
<< " to " << sf_vtable_offset << "\n";
|
||||
}
|
||||
|
||||
// the parent types (classe or union) of the two member
|
||||
// functions.
|
||||
class_or_union_sptr f =
|
||||
is_class_or_union_type(is_method_type(ff->get_type())->get_class_type());
|
||||
class_or_union_sptr s =
|
||||
is_class_or_union_type(is_method_type(sf->get_type())->get_class_type());
|
||||
|
||||
class_decl_sptr fc = is_class_type(f);
|
||||
class_decl_sptr sc = is_class_type(s);
|
||||
|
||||
// Detect if the virtual member function changes above
|
||||
// introduced a vtable change or not.
|
||||
bool vtable_added = false, vtable_removed = false;
|
||||
if (!f->get_is_declaration_only() && !s->get_is_declaration_only())
|
||||
{
|
||||
if (fc && sc)
|
||||
{
|
||||
vtable_added = !fc->has_vtable() && sc->has_vtable();
|
||||
vtable_removed = fc->has_vtable() && !sc->has_vtable();
|
||||
}
|
||||
}
|
||||
bool vtable_changed = ((ff_is_virtual != sf_is_virtual)
|
||||
|| (ff_vtable_offset != sf_vtable_offset));
|
||||
bool incompatible_change = (ff_vtable_offset != sf_vtable_offset);
|
||||
|
||||
if (vtable_added)
|
||||
out << indent
|
||||
<< " note that a vtable was added to "
|
||||
<< fc->get_pretty_representation()
|
||||
<< "\n";
|
||||
else if (vtable_removed)
|
||||
out << indent
|
||||
<< " note that the vtable was removed from "
|
||||
<< fc->get_pretty_representation()
|
||||
<< "\n";
|
||||
else if (vtable_changed)
|
||||
{
|
||||
out << indent;
|
||||
if (incompatible_change)
|
||||
out << " note that this is an ABI incompatible "
|
||||
"change to the vtable of ";
|
||||
else
|
||||
out << " note that this induces a change to the vtable of ";
|
||||
out << fc->get_pretty_representation()
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Report about function type differences.
|
||||
@@ -1648,15 +1706,20 @@ default_reporter::report(const var_diff& d, ostream& out,
|
||||
decl_base_sptr first = d.first_var(), second = d.second_var();
|
||||
string n = first->get_pretty_representation();
|
||||
|
||||
report_name_size_and_alignment_changes(first, second,
|
||||
d.context(),
|
||||
out, indent);
|
||||
if (!d.is_filtered_out_without_looking_at_allowed_changes())
|
||||
{
|
||||
report_name_size_and_alignment_changes(first, second,
|
||||
d.context(),
|
||||
out, indent);
|
||||
|
||||
maybe_report_diff_for_symbol(d.first_var()->get_symbol(),
|
||||
d.second_var()->get_symbol(),
|
||||
d.context(), out, indent);
|
||||
maybe_report_diff_for_symbol(d.first_var()->get_symbol(),
|
||||
d.second_var()->get_symbol(),
|
||||
d.context(), out, indent);
|
||||
|
||||
maybe_report_diff_for_member(first, second, d.context(), out, indent);
|
||||
maybe_report_diff_for_member(first, second, d.context(), out, indent);
|
||||
|
||||
maybe_report_diff_for_variable(first, second, d.context(), out, indent);
|
||||
}
|
||||
|
||||
if (diff_sptr dif = d.type_diff())
|
||||
{
|
||||
@@ -1842,7 +1905,7 @@ default_reporter::report(const corpus_diff& d, ostream& out,
|
||||
function_decl_sptr fn = (*i)->first_function_decl();
|
||||
out << indent << " [C] '"
|
||||
<< fn->get_pretty_representation() << "'";
|
||||
report_loc_info((*i)->second_function_decl(), *ctxt, out);
|
||||
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
|
||||
@@ -1859,7 +1922,7 @@ default_reporter::report(const corpus_diff& d, ostream& out,
|
||||
// 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()))
|
||||
&& 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
|
||||
@@ -1935,7 +1998,7 @@ default_reporter::report(const corpus_diff& d, ostream& out,
|
||||
emitted = true;
|
||||
}
|
||||
if (emitted)
|
||||
out << "\n";
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
if (ctxt->show_added_vars())
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
+488
-188
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 Red Hat, Inc.
|
||||
// Copyright (C) 2022-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -61,7 +61,7 @@ elf_based_reader::elf_based_reader(const std::string& elf_path,
|
||||
elf_based_reader::~elf_based_reader()
|
||||
{delete priv_;}
|
||||
|
||||
/// Reset (re-initialize) the resources used by the current reader.
|
||||
/// (re)Initialize) the resources used by the current reader.
|
||||
///
|
||||
/// This frees the resources of the current reader and gets it ready
|
||||
/// to read data from another ELF file.
|
||||
@@ -71,13 +71,28 @@ elf_based_reader::~elf_based_reader()
|
||||
/// @param debug_info_root_paths a vector of paths to look into for
|
||||
/// split debug info files.
|
||||
void
|
||||
elf_based_reader::reset(const std::string& elf_path,
|
||||
const vector<char**>& debug_info_root_paths)
|
||||
elf_based_reader::initialize(const std::string& elf_path,
|
||||
const vector<char**>& debug_info_root_paths)
|
||||
{
|
||||
elf::reader::reset(elf_path, debug_info_root_paths);
|
||||
elf::reader::initialize(elf_path, debug_info_root_paths);
|
||||
priv_->initialize();
|
||||
}
|
||||
|
||||
/// (re)Initialize the resources used by the current reader.
|
||||
///
|
||||
/// This invokes fe_iface::initialize as wel as the virtual pure
|
||||
/// elf_based_reader::initialize() interface.
|
||||
///
|
||||
/// @param corpus_path path to the corpus to be built.
|
||||
void
|
||||
elf_based_reader::initialize(const std::string& corpus_path)
|
||||
{
|
||||
fe_iface::initialize(corpus_path);
|
||||
vector<char**> v;
|
||||
initialize(corpus_path, v, /*load_all_type=*/false,
|
||||
/*linux_kernel_mode=*/false);
|
||||
}
|
||||
|
||||
/// Read an ABI corpus and add it to a given corpus group.
|
||||
///
|
||||
/// @param group the corpus group to consider. The new corpus is
|
||||
@@ -92,10 +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);
|
||||
|
||||
if (status & fe_iface::STATUS_OK)
|
||||
group.add_corpus(corp);
|
||||
return corp;
|
||||
}
|
||||
|
||||
|
||||
+14
-7
@@ -1,17 +1,19 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2020-2022 Google, Inc.
|
||||
// Copyright (C) 2020-2023 Google, Inc.
|
||||
|
||||
/// @file
|
||||
///
|
||||
/// This contains the definitions of the ELF utilities for the dwarf reader.
|
||||
#include "config.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include <sstream>
|
||||
#include "abg-elf-helpers.h"
|
||||
#include "abg-tools-utils.h"
|
||||
|
||||
@@ -920,10 +922,11 @@ bool
|
||||
get_crc_for_symbol(Elf* elf_handle, GElf_Sym* crc_symbol, uint32_t& crc_value)
|
||||
{
|
||||
size_t crc_section_index = crc_symbol->st_shndx;
|
||||
uint64_t crc_symbol_value = crc_symbol->st_value;
|
||||
GElf_Addr crc_symbol_address =
|
||||
maybe_adjust_et_rel_sym_addr_to_abs_addr(elf_handle, crc_symbol);
|
||||
if (crc_section_index == SHN_ABS)
|
||||
{
|
||||
crc_value = crc_symbol_value;
|
||||
crc_value = crc_symbol_address;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -940,10 +943,10 @@ get_crc_for_symbol(Elf* elf_handle, GElf_Sym* crc_symbol, uint32_t& crc_value)
|
||||
if (kcrctab_data == NULL)
|
||||
return false;
|
||||
|
||||
if (crc_symbol_value < sheader->sh_addr)
|
||||
if (crc_symbol_address < sheader->sh_addr)
|
||||
return false;
|
||||
|
||||
size_t offset = crc_symbol_value - sheader->sh_addr;
|
||||
size_t offset = crc_symbol_address - sheader->sh_addr;
|
||||
if (offset + sizeof(uint32_t) > kcrctab_data->d_size
|
||||
|| offset + sizeof(uint32_t) > sheader->sh_size)
|
||||
return false;
|
||||
@@ -1519,13 +1522,17 @@ get_soname_of_elf_file(const string& path, string &soname)
|
||||
Elf_Scn* scn = gelf_offscn (elf, phdr->p_offset);
|
||||
GElf_Shdr shdr_mem;
|
||||
GElf_Shdr* shdr = gelf_getshdr (scn, &shdr_mem);
|
||||
if (!(shdr == NULL || (shdr->sh_type == SHT_DYNAMIC
|
||||
|| shdr->sh_type == SHT_PROGBITS)))
|
||||
// This program header doesn't look like one we are
|
||||
// looking for. Skip to the next.
|
||||
continue;
|
||||
|
||||
size_t entsize = (shdr != NULL && shdr->sh_entsize != 0
|
||||
? shdr->sh_entsize
|
||||
: gelf_fsize (elf, ELF_T_DYN, 1, EV_CURRENT));
|
||||
int maxcnt = (shdr != NULL
|
||||
? shdr->sh_size / entsize : INT_MAX);
|
||||
ABG_ASSERT (shdr == NULL || (shdr->sh_type == SHT_DYNAMIC
|
||||
|| shdr->sh_type == SHT_PROGBITS));
|
||||
Elf_Data* data = elf_getdata (scn, NULL);
|
||||
if (data == NULL)
|
||||
break;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2020-2022 Google, Inc.
|
||||
// Copyright (C) 2020-2023 Google, Inc.
|
||||
|
||||
/// @file
|
||||
///
|
||||
|
||||
+126
-28
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2022 Red Hat, Inc.
|
||||
// Copyright (C) 2022-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -132,6 +132,11 @@ find_alt_dwarf_debug_info_path(const vector<char**> root_dirs,
|
||||
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();
|
||||
@@ -225,10 +230,10 @@ find_alt_dwarf_debug_info(Dwfl_Module *elf_module,
|
||||
// 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.
|
||||
int fd = open(alt_file_path.c_str(), O_RDONLY);
|
||||
if (fd == -1)
|
||||
alt_fd = open(alt_file_path.c_str(), O_RDONLY);
|
||||
if (alt_fd == -1)
|
||||
return result;
|
||||
result = dwarf_begin(fd, DWARF_C_READ);
|
||||
result = dwarf_begin(alt_fd, DWARF_C_READ);
|
||||
|
||||
#ifdef LIBDW_HAS_DWARF_GETALT
|
||||
Dwarf_Addr bias = 0;
|
||||
@@ -271,7 +276,10 @@ struct reader::priv
|
||||
string alt_dwarf_path;
|
||||
int alt_dwarf_fd = 0;
|
||||
Elf_Scn* ctf_section = nullptr;
|
||||
int alt_ctf_fd = 0;
|
||||
Elf* alt_ctf_handle = nullptr;
|
||||
Elf_Scn* alt_ctf_section = nullptr;
|
||||
Elf_Scn* btf_section = nullptr;
|
||||
|
||||
priv(reader& reeder, const std::string& elf_path,
|
||||
const vector<char**>& debug_info_roots)
|
||||
@@ -281,6 +289,12 @@ struct reader::priv
|
||||
initialize(debug_info_roots);
|
||||
}
|
||||
|
||||
~priv()
|
||||
{
|
||||
clear_alt_dwarf_debug_info_data();
|
||||
clear_alt_ctf_debug_info_data();
|
||||
}
|
||||
|
||||
/// Reset the private data of @elf elf::reader.
|
||||
///
|
||||
/// @param debug_info_roots the vector of new directories where to
|
||||
@@ -288,11 +302,26 @@ struct reader::priv
|
||||
void
|
||||
initialize(const vector<char**>& debug_info_roots)
|
||||
{
|
||||
debug_info_root_paths = debug_info_roots;
|
||||
clear_alt_dwarf_debug_info_data();
|
||||
clear_alt_ctf_debug_info_data();
|
||||
|
||||
elf_handle = nullptr;
|
||||
symtab_section = nullptr;
|
||||
elf_architecture.clear();
|
||||
dt_needed.clear();
|
||||
symt.reset();
|
||||
debug_info_root_paths = debug_info_roots;
|
||||
memset(&offline_callbacks, 0, sizeof(offline_callbacks));
|
||||
dwfl_handle.reset();
|
||||
elf_module = nullptr;
|
||||
elf_handle = nullptr;
|
||||
dwarf_handle = nullptr;
|
||||
alt_dwarf_handle = nullptr;
|
||||
alt_dwarf_path.clear();
|
||||
alt_dwarf_fd = 0;
|
||||
ctf_section = nullptr;
|
||||
alt_ctf_section = nullptr;
|
||||
alt_ctf_handle = nullptr;
|
||||
alt_ctf_fd = 0;
|
||||
}
|
||||
|
||||
/// Setup the necessary plumbing to open the ELF file and find all
|
||||
@@ -348,6 +377,23 @@ struct reader::priv
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Clear the resources related to the alternate DWARF data.
|
||||
void
|
||||
clear_alt_dwarf_debug_info_data()
|
||||
{
|
||||
if (alt_dwarf_fd)
|
||||
{
|
||||
if (alt_dwarf_handle)
|
||||
{
|
||||
dwarf_end(alt_dwarf_handle);
|
||||
alt_dwarf_handle = nullptr;
|
||||
}
|
||||
close(alt_dwarf_fd);
|
||||
alt_dwarf_fd = 0;
|
||||
}
|
||||
alt_dwarf_path.clear();
|
||||
}
|
||||
|
||||
/// Locate the DWARF debug info in the ELF file.
|
||||
///
|
||||
/// This also knows how to locate split debug info.
|
||||
@@ -379,6 +425,22 @@ struct reader::priv
|
||||
alt_dwarf_fd);
|
||||
}
|
||||
|
||||
/// Clear the resources related to the alternate CTF data.
|
||||
void
|
||||
clear_alt_ctf_debug_info_data()
|
||||
{
|
||||
if (alt_ctf_fd)
|
||||
{
|
||||
close(alt_ctf_fd);
|
||||
alt_ctf_fd = 0;
|
||||
}
|
||||
if (alt_ctf_handle)
|
||||
{
|
||||
elf_end(alt_ctf_handle);
|
||||
alt_ctf_handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/// Locate the CTF "alternate" debug information associated with the
|
||||
/// current ELF file ( and split out somewhere else).
|
||||
///
|
||||
@@ -386,6 +448,9 @@ struct reader::priv
|
||||
void
|
||||
locate_alt_ctf_debug_info()
|
||||
{
|
||||
if (alt_ctf_section)
|
||||
return;
|
||||
|
||||
Elf_Scn *section =
|
||||
elf_helpers::find_section(elf_handle,
|
||||
".gnu_debuglink",
|
||||
@@ -405,24 +470,20 @@ struct reader::priv
|
||||
if (!tools_utils::find_file_under_dir(*path, name, file_path))
|
||||
continue;
|
||||
|
||||
int fd;
|
||||
if ((fd = open(file_path.c_str(), O_RDONLY)) == -1)
|
||||
if ((alt_ctf_fd = open(file_path.c_str(), O_RDONLY)) == -1)
|
||||
continue;
|
||||
|
||||
Elf *hdl;
|
||||
if ((hdl = elf_begin(fd, ELF_C_READ, nullptr)) == nullptr)
|
||||
{
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
if ((alt_ctf_handle = elf_begin(alt_ctf_fd,
|
||||
ELF_C_READ,
|
||||
nullptr)) == nullptr)
|
||||
continue;
|
||||
|
||||
// unlikely .ctf was designed to be present in stripped file
|
||||
alt_ctf_section =
|
||||
elf_helpers::find_section(hdl, ".ctf", SHT_PROGBITS);
|
||||
break;
|
||||
elf_helpers::find_section(alt_ctf_handle, ".ctf", SHT_PROGBITS);
|
||||
|
||||
elf_end(hdl);
|
||||
close(fd);
|
||||
if (alt_ctf_section)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,8 +527,8 @@ reader::reader(const string& elf_path,
|
||||
reader::~reader()
|
||||
{delete priv_;}
|
||||
|
||||
/// Resets (erase) the resources used by the current @ref
|
||||
/// elf::reader type.
|
||||
/// Re-initialize the resources used by the current @ref elf::reader
|
||||
/// type.
|
||||
///
|
||||
/// This lets the reader in a state where it's ready to read from
|
||||
/// another ELF file.
|
||||
@@ -477,11 +538,10 @@ reader::~reader()
|
||||
/// @param debug_info_roots a vector of directory paths to look into
|
||||
/// for split debug information files.
|
||||
void
|
||||
reader::reset(const std::string& elf_path,
|
||||
const vector<char**>& debug_info_roots)
|
||||
reader::initialize(const std::string& elf_path,
|
||||
const vector<char**>& debug_info_roots)
|
||||
{
|
||||
fe_iface::options_type opts = options();
|
||||
fe_iface::reset(elf_path, opts.env);
|
||||
fe_iface::initialize(elf_path);
|
||||
corpus_path(elf_path);
|
||||
priv_->initialize(debug_info_roots);
|
||||
priv_->crack_open_elf_file();
|
||||
@@ -489,6 +549,20 @@ reader::reset(const std::string& elf_path,
|
||||
priv_->locate_ctf_debug_info();
|
||||
}
|
||||
|
||||
/// Re-initialize the resources used by the current @ref elf::reader
|
||||
/// type.
|
||||
///
|
||||
/// This lets the reader in a state where it's ready to read from
|
||||
/// another ELF file.
|
||||
///
|
||||
/// @param elf_path the new ELF path to read from.
|
||||
void
|
||||
reader::initialize(const std::string& elf_path)
|
||||
{
|
||||
vector<char**> v;
|
||||
initialize(elf_path, v);
|
||||
}
|
||||
|
||||
/// Getter of the vector of directory paths to look into for split
|
||||
/// debug information files.
|
||||
///
|
||||
@@ -547,6 +621,13 @@ bool
|
||||
reader::has_ctf_debug_info() const
|
||||
{return (priv_->ctf_section != nullptr);}
|
||||
|
||||
/// Test if the binary has BTF debug info.
|
||||
///
|
||||
/// @return true iff the binary has BTF debug info
|
||||
bool
|
||||
reader::has_btf_debug_info() const
|
||||
{return (priv_->btf_section != nullptr);}
|
||||
|
||||
/// Getter of the handle use to access DWARF information from the
|
||||
/// alternate split DWARF information.
|
||||
///
|
||||
@@ -642,6 +723,20 @@ reader::find_alternate_ctf_section() const
|
||||
return priv_->alt_ctf_section;
|
||||
}
|
||||
|
||||
/// Find and return a pointer to the BTF section of the current ELF
|
||||
/// file.
|
||||
///
|
||||
/// @return a pointer to the BTF section of the current ELF file.
|
||||
const Elf_Scn*
|
||||
reader::find_btf_section() const
|
||||
{
|
||||
if (priv_->btf_section == nullptr)
|
||||
priv_->btf_section =
|
||||
elf_helpers::find_section(priv_->elf_handle,
|
||||
".BTF", SHT_PROGBITS);
|
||||
return priv_->btf_section;
|
||||
}
|
||||
|
||||
/// Get the value of the DT_NEEDED property of the current ELF file.
|
||||
///
|
||||
/// @return the value of the DT_NEEDED property.
|
||||
@@ -881,11 +976,14 @@ reader::read_corpus(status& status)
|
||||
corpus()->set_architecture_name(elf_architecture());
|
||||
|
||||
// See if we could find symbol tables.
|
||||
if (!symtab() || !symtab()->has_symbols())
|
||||
if (!symtab())
|
||||
{
|
||||
status |= STATUS_NO_SYMBOLS_FOUND;
|
||||
// We found no ELF symbol, so we can't handle the binary.
|
||||
return corpus_sptr();
|
||||
status |= STATUS_NO_SYMBOLS_FOUND | STATUS_OK;
|
||||
// We found no ELF symbol, so we can't handle the binary. Note
|
||||
// that we could have found a symbol table with no defined &
|
||||
// exported ELF symbols in it. Both cases are handled as an
|
||||
// empty corpus.
|
||||
return corpus();
|
||||
}
|
||||
|
||||
// Set symbols information to the corpus.
|
||||
|
||||
+9
-12
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2022 Red Hat, Inc.
|
||||
// Copyright (C) 2022-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -43,11 +43,11 @@ struct fe_iface::priv
|
||||
void
|
||||
initialize()
|
||||
{
|
||||
//TODO: initialize the options.
|
||||
corpus_path.clear();
|
||||
dt_soname.clear();
|
||||
suppressions.clear();
|
||||
corpus_group.reset();
|
||||
corpus.reset();
|
||||
}
|
||||
}; //end struct fe_iface::priv
|
||||
|
||||
@@ -78,14 +78,11 @@ fe_iface::~fe_iface()
|
||||
///
|
||||
/// @param corpus_path the path to the file for which a new corpus is
|
||||
/// to be created.
|
||||
///
|
||||
/// @param e the environment in which the Front End operates.
|
||||
void
|
||||
fe_iface::reset(const std::string& corpus_path,
|
||||
environment& e)
|
||||
fe_iface::initialize(const std::string& corpus_path)
|
||||
{
|
||||
delete priv_;
|
||||
priv_ = new fe_iface::priv(corpus_path, e);
|
||||
priv_->initialize();
|
||||
priv_->corpus_path = corpus_path;
|
||||
}
|
||||
|
||||
/// Getter of the the options of the current Front End Interface.
|
||||
@@ -310,7 +307,7 @@ fe_iface::maybe_add_fn_to_exported_decls(const function_decl* fn)
|
||||
if (fn)
|
||||
if (corpus::exported_decls_builder* b =
|
||||
corpus()->get_exported_decls_builder().get())
|
||||
b->maybe_add_fn_to_exported_fns(fn);
|
||||
b->maybe_add_fn_to_exported_fns(const_cast<function_decl*>(fn));
|
||||
}
|
||||
|
||||
/// Try and add the representation of the ABI of a variable to the set
|
||||
@@ -397,13 +394,13 @@ status_to_diagnostic_string(fe_iface::status s)
|
||||
std::string str;
|
||||
|
||||
if (s & fe_iface::STATUS_DEBUG_INFO_NOT_FOUND)
|
||||
str += "could not find debug info\n";
|
||||
str += "could not find debug info";
|
||||
|
||||
if (s & fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
|
||||
str += "could not find alternate debug info\n";
|
||||
str += "could not find alternate debug info";
|
||||
|
||||
if (s & fe_iface::STATUS_NO_SYMBOLS_FOUND)
|
||||
str += "could not load ELF symbols\n";
|
||||
str += "could not load ELF symbols";
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
|
||||
|
||||
+5
-4
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -145,7 +145,7 @@ char_is_function_name_char(int b)
|
||||
static bool
|
||||
char_is_function_argument_char(int b)
|
||||
{
|
||||
if (char_is_delimiter(b) || b == '(' || b == ')')
|
||||
if (b == '(' || b == ')')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -1353,7 +1353,7 @@ public:
|
||||
}
|
||||
|
||||
list_property_value_sptr list = read_list_property_value();
|
||||
if (list->get_content().size() == 1)
|
||||
if (list && list->get_content().size() == 1)
|
||||
result.reset(new string_property_value(list->get_content()[0]));
|
||||
else
|
||||
result = list;
|
||||
@@ -1365,7 +1365,7 @@ public:
|
||||
///
|
||||
/// A string is just a contiguous set of characters that test
|
||||
/// positive when passed to
|
||||
/// read_context::char_is_property_name_char().
|
||||
/// read_context::char_is_property_value_char().
|
||||
///
|
||||
/// Note that all escaped characters are suitable to be in a string.
|
||||
///
|
||||
@@ -1440,6 +1440,7 @@ public:
|
||||
char c = 0;
|
||||
read_next_char(c);
|
||||
ABG_ASSERT(c == ',');
|
||||
skip_white_spaces();
|
||||
}
|
||||
|
||||
if (!content.empty())
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2016-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2016-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
|
||||
+316
-85
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2016-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2016-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -337,7 +337,7 @@ struct type_base::priv
|
||||
|
||||
/// If the current canonical type was set as the result of the
|
||||
/// "canonical type propagation optimization", then clear it.
|
||||
void
|
||||
bool
|
||||
clear_propagated_canonical_type()
|
||||
{
|
||||
if (canonical_type_propagated_ && !propagated_canonical_type_confirmed_)
|
||||
@@ -345,7 +345,9 @@ struct type_base::priv
|
||||
canonical_type.reset();
|
||||
naked_canonical_type = nullptr;
|
||||
set_canonical_type_propagated(false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}; // end struct type_base::priv
|
||||
|
||||
@@ -369,6 +371,13 @@ typedef std::pair<uint64_t, uint64_t> uint64_t_pair_type;
|
||||
/// A convenience typedef for a set of @ref uint64_t_pair
|
||||
typedef unordered_set<uint64_t_pair_type,
|
||||
uint64_t_pair_hash> uint64_t_pairs_set_type;
|
||||
|
||||
/// A convenience typedef for a set of pointer to @ref class_or_union
|
||||
typedef unordered_set<const class_or_union*> class_set_type;
|
||||
|
||||
/// A convenience typedef for a set of pointer to @ref function_type.
|
||||
typedef unordered_set<const function_type*> fn_set_type;
|
||||
|
||||
/// A convenience typedef for a map which key is a pair of uint64_t
|
||||
/// and which value is a boolean. This is initially intended to cache
|
||||
/// the result of comparing two (sub-)types.
|
||||
@@ -382,17 +391,20 @@ struct environment::priv
|
||||
canonical_types_map_type canonical_types_;
|
||||
mutable vector<type_base_sptr> sorted_canonical_types_;
|
||||
type_base_sptr void_type_;
|
||||
type_base_sptr void_pointer_type_;
|
||||
type_base_sptr variadic_marker_type_;
|
||||
// The set of pairs of class types being currently compared. It's
|
||||
// used to avoid endless loops while recursively comparing types.
|
||||
// This should be empty when none of the 'equal' overloads are
|
||||
// currently being invoked.
|
||||
uint64_t_pairs_set_type classes_being_compared_;
|
||||
class_set_type left_classes_being_compared_;
|
||||
class_set_type right_classes_being_compared_;
|
||||
// The set of pairs of function types being currently compared. It's used
|
||||
// to avoid endless loops while recursively comparing types. This
|
||||
// should be empty when none of the 'equal' overloads are currently
|
||||
// being invoked.
|
||||
uint64_t_pairs_set_type fn_types_being_compared_;
|
||||
fn_set_type left_fn_types_being_compared_;
|
||||
fn_set_type right_fn_types_being_compared_;
|
||||
// This is a cache for the result of comparing two sub-types (of
|
||||
// either class or function types) that are designated by their
|
||||
// memory address in the IR.
|
||||
@@ -449,6 +461,14 @@ struct environment::priv
|
||||
// must be cleared.
|
||||
pointer_set types_with_non_confirmed_propagated_ct_;
|
||||
pointer_set recursive_types_;
|
||||
#ifdef WITH_DEBUG_CT_PROPAGATION
|
||||
// Set of types which propagated canonical type has been cleared
|
||||
// during the "canonical type propagation optimization" phase. Those
|
||||
// types are tracked in this set to ensure that they are later
|
||||
// canonicalized. This means that at the end of the
|
||||
// canonicalization process, this set must be empty.
|
||||
mutable pointer_set types_with_cleared_propagated_ct_;
|
||||
#endif
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
// This is used for debugging purposes.
|
||||
// When abidw is used with the option --debug-abidiff, some
|
||||
@@ -474,6 +494,7 @@ struct environment::priv
|
||||
bool decl_only_class_equals_definition_;
|
||||
bool use_enum_binary_only_equality_;
|
||||
bool allow_type_comparison_results_caching_;
|
||||
bool do_log_;
|
||||
optional<bool> analyze_exported_interfaces_only_;
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
bool self_comparison_debug_on_;
|
||||
@@ -500,7 +521,8 @@ struct environment::priv
|
||||
do_on_the_fly_canonicalization_(true),
|
||||
decl_only_class_equals_definition_(false),
|
||||
use_enum_binary_only_equality_(true),
|
||||
allow_type_comparison_results_caching_(false)
|
||||
allow_type_comparison_results_caching_(false),
|
||||
do_log_(false)
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
,
|
||||
self_comparison_debug_on_(false)
|
||||
@@ -533,6 +555,14 @@ struct environment::priv
|
||||
allow_type_comparison_results_caching() const
|
||||
{return allow_type_comparison_results_caching_;}
|
||||
|
||||
void
|
||||
do_log(bool f)
|
||||
{do_log_ = f;}
|
||||
|
||||
bool
|
||||
do_log() const
|
||||
{return do_log_;}
|
||||
|
||||
/// Cache the result of comparing two sub-types.
|
||||
///
|
||||
/// @param first the first sub-type that has been compared. Its
|
||||
@@ -605,48 +635,6 @@ struct environment::priv
|
||||
clear_type_comparison_results_cache()
|
||||
{type_comparison_results_cache_.clear();}
|
||||
|
||||
/// Dumps a textual representation (to the standard error output) of
|
||||
/// the content of the set of classes being currently compared using
|
||||
/// the @ref equal overloads.
|
||||
///
|
||||
/// This function is for debugging purposes.
|
||||
void
|
||||
dump_classes_being_compared()
|
||||
{
|
||||
std::cerr << "classes being compared: " << classes_being_compared_.size()
|
||||
<< "\n"
|
||||
<< "=====================================\n";
|
||||
for (auto& p : classes_being_compared_)
|
||||
{
|
||||
class_or_union* c = reinterpret_cast<class_or_union*>(p.first);
|
||||
std::cerr << "'" << c->get_pretty_representation()
|
||||
<< " / (" << std::hex << p.first << "," << p.second << ")"
|
||||
<< "'\n";
|
||||
}
|
||||
std::cerr << "=====================================\n";
|
||||
}
|
||||
|
||||
/// Dumps a textual representation (to the standard error output) of
|
||||
/// the content of the set of classes being currently compared using
|
||||
/// the @ref equal overloads.
|
||||
///
|
||||
/// This function is for debugging purposes.
|
||||
void
|
||||
dump_fn_types_being_compared()
|
||||
{
|
||||
std::cerr << "fn_types being compared: " << fn_types_being_compared_.size()
|
||||
<< "\n"
|
||||
<< "=====================================\n";
|
||||
for (auto& p : fn_types_being_compared_)
|
||||
{
|
||||
function_type* c = reinterpret_cast<function_type*>(p.first);
|
||||
std::cerr << "'" << c->get_pretty_representation()
|
||||
<< " / (" << std::hex << p.first << "," << p.second << ")"
|
||||
<< "'\n";
|
||||
}
|
||||
std::cerr << "=====================================\n";
|
||||
}
|
||||
|
||||
/// Push a pair of operands on the stack of operands of the current
|
||||
/// type comparison, during type canonicalization.
|
||||
///
|
||||
@@ -827,6 +815,11 @@ struct environment::priv
|
||||
dest.priv_->canonical_type = canonical;
|
||||
dest.priv_->naked_canonical_type = canonical.get();
|
||||
dest.priv_->set_canonical_type_propagated(true);
|
||||
#ifdef WITH_DEBUG_CT_PROPAGATION
|
||||
// If dest was previously a type which propagated canonical type
|
||||
// has been cleared, let the book-keeping system know.
|
||||
erase_type_with_cleared_propagated_canonical_type(&dest);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -845,13 +838,14 @@ struct environment::priv
|
||||
for (auto i : types_with_non_confirmed_propagated_ct_)
|
||||
{
|
||||
type_base *t = reinterpret_cast<type_base*>(i);
|
||||
ABG_ASSERT(t->get_environment().priv_->is_recursive_type(t)
|
||||
|| t->priv_->depends_on_recursive_type());
|
||||
t->priv_->set_does_not_depend_on_recursive_type(dependant_type);
|
||||
if (!t->priv_->depends_on_recursive_type())
|
||||
{
|
||||
to_remove.insert(i);
|
||||
t->priv_->set_propagated_canonical_type_confirmed(true);
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
check_abixml_canonical_type_propagation_during_self_comp(t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -883,6 +877,9 @@ struct environment::priv
|
||||
env.priv_->remove_from_types_with_non_confirmed_propagated_ct(t);
|
||||
env.priv_->set_is_not_recursive(t);
|
||||
t->priv_->set_propagated_canonical_type_confirmed(true);
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
check_abixml_canonical_type_propagation_during_self_comp(t);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Mark all the types that have been the target of canonical type
|
||||
@@ -899,14 +896,65 @@ struct environment::priv
|
||||
for (auto i : types_with_non_confirmed_propagated_ct_)
|
||||
{
|
||||
type_base *t = reinterpret_cast<type_base*>(i);
|
||||
ABG_ASSERT(t->get_environment().priv_->is_recursive_type(t)
|
||||
|| t->priv_->depends_on_recursive_type());
|
||||
t->priv_->set_does_not_depend_on_recursive_type();
|
||||
t->priv_->set_propagated_canonical_type_confirmed(true);
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
check_abixml_canonical_type_propagation_during_self_comp(t);
|
||||
#endif
|
||||
}
|
||||
types_with_non_confirmed_propagated_ct_.clear();
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_CT_PROPAGATION
|
||||
/// Getter for the set of types which propagated canonical type has
|
||||
/// been cleared during the "canonical type propagation
|
||||
/// optimization" phase. Those types are tracked in this set to
|
||||
/// ensure that they are later canonicalized. This means that at
|
||||
/// the end of the canonicalization process, this set must be empty.
|
||||
///
|
||||
/// @return the set of types which propagated canonical type has
|
||||
/// been cleared.
|
||||
const pointer_set&
|
||||
types_with_cleared_propagated_ct() const
|
||||
{return types_with_cleared_propagated_ct_;}
|
||||
|
||||
/// Getter for the set of types which propagated canonical type has
|
||||
/// been cleared during the "canonical type propagation
|
||||
/// optimization" phase. Those types are tracked in this set to
|
||||
/// ensure that they are later canonicalized. This means that at
|
||||
/// the end of the canonicalization process, this set must be empty.
|
||||
///
|
||||
/// @return the set of types which propagated canonical type has
|
||||
/// been cleared.
|
||||
pointer_set&
|
||||
types_with_cleared_propagated_ct()
|
||||
{return types_with_cleared_propagated_ct_;}
|
||||
|
||||
/// Record a type which propagated canonical type has been cleared
|
||||
/// during the "canonical type propagation optimization phase".
|
||||
///
|
||||
/// @param t the type to record.
|
||||
void
|
||||
record_type_with_cleared_propagated_canonical_type(const type_base* t)
|
||||
{
|
||||
uintptr_t ptr = reinterpret_cast<uintptr_t>(t);
|
||||
types_with_cleared_propagated_ct_.insert(ptr);
|
||||
}
|
||||
|
||||
/// Erase a type (which propagated canonical type has been cleared
|
||||
/// during the "canonical type propagation optimization phase") from
|
||||
/// the set of types that have been recorded by the invocation of
|
||||
/// record_type_with_cleared_propagated_canonical_type()
|
||||
///
|
||||
/// @param t the type to erase from the set.
|
||||
void
|
||||
erase_type_with_cleared_propagated_canonical_type(const type_base* t)
|
||||
{
|
||||
uintptr_t ptr = reinterpret_cast<uintptr_t>(t);
|
||||
types_with_cleared_propagated_ct_.erase(ptr);
|
||||
}
|
||||
#endif //WITH_DEBUG_CT_PROPAGATION
|
||||
|
||||
/// Collect the types that depends on a given "target" type.
|
||||
///
|
||||
/// Walk a set of types and if they depend directly or indirectly on
|
||||
@@ -974,7 +1022,7 @@ struct environment::priv
|
||||
type_base_sptr canonical = t->priv_->canonical_type.lock();
|
||||
if (canonical)
|
||||
{
|
||||
t->priv_->clear_propagated_canonical_type();
|
||||
clear_propagated_canonical_type(t);
|
||||
t->priv_->set_does_not_depend_on_recursive_type();
|
||||
}
|
||||
}
|
||||
@@ -1008,18 +1056,37 @@ struct environment::priv
|
||||
|
||||
const environment& env = t->get_environment();
|
||||
env.priv_->cancel_ct_propagation_for_types_dependant_on(t);
|
||||
if (t->priv_->depends_on_recursive_type()
|
||||
|| env.priv_->is_recursive_type(t))
|
||||
// This cannot carry any tentative canonical type at this
|
||||
// point.
|
||||
clear_propagated_canonical_type(t);
|
||||
// Reset the marking of the type as it no longer carries a
|
||||
// tentative canonical type that might be later canceled.
|
||||
t->priv_->set_does_not_depend_on_recursive_type();
|
||||
env.priv_->remove_from_types_with_non_confirmed_propagated_ct(t);
|
||||
env.priv_->clear_type_comparison_results_cache();
|
||||
}
|
||||
|
||||
/// Clear the propagated canonical type of a given type.
|
||||
///
|
||||
/// This function also updates the book-keeping of the set of types
|
||||
/// which propagated canonical types have been cleared.
|
||||
///
|
||||
/// Please note that at the end of the canonicalization of all the
|
||||
/// types in the system, all the types which propagated canonical
|
||||
/// type has been cleared must be canonicalized.
|
||||
///
|
||||
/// @param t the type to
|
||||
void
|
||||
clear_propagated_canonical_type(const type_base *t)
|
||||
{
|
||||
if (t->priv_->clear_propagated_canonical_type())
|
||||
{
|
||||
// This cannot carry any tentative canonical type at this
|
||||
// point.
|
||||
if (t->priv_->canonical_type_propagated()
|
||||
&& !t->priv_->propagated_canonical_type_confirmed())
|
||||
t->priv_->clear_propagated_canonical_type();
|
||||
// Reset the marking of the type as it no longer carries a
|
||||
// tentative canonical type that might be later cancelled.
|
||||
t->priv_->set_does_not_depend_on_recursive_type();
|
||||
env.priv_->remove_from_types_with_non_confirmed_propagated_ct(t);
|
||||
#ifdef WITH_DEBUG_CT_PROPAGATION
|
||||
// let the book-keeping system know that t has its propagated
|
||||
// canonical type cleared.
|
||||
record_type_with_cleared_propagated_canonical_type(t)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1047,7 +1114,64 @@ struct environment::priv
|
||||
types_with_non_confirmed_propagated_ct_.erase(i);
|
||||
}
|
||||
|
||||
/// Cancel the propagated canonical types of all the types which
|
||||
/// propagated canonical type have not yet been confirmed.
|
||||
void
|
||||
cancel_all_non_confirmed_propagated_canonical_types()
|
||||
{
|
||||
vector<uintptr_t> to_erase;
|
||||
for (auto i : types_with_non_confirmed_propagated_ct_)
|
||||
to_erase.push_back(i);
|
||||
|
||||
for (auto i : to_erase)
|
||||
{
|
||||
type_base *t = reinterpret_cast<type_base*>(i);
|
||||
cancel_ct_propagation(t);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
|
||||
const unordered_map<string, uintptr_t>&
|
||||
get_type_id_canonical_type_map() const
|
||||
{return type_id_canonical_type_map_;}
|
||||
|
||||
unordered_map<string, uintptr_t>&
|
||||
get_type_id_canonical_type_map()
|
||||
{return type_id_canonical_type_map_;}
|
||||
|
||||
const unordered_map<uintptr_t, string>&
|
||||
get_pointer_type_id_map() const
|
||||
{return pointer_type_id_map_;}
|
||||
|
||||
unordered_map<uintptr_t, string>&
|
||||
get_pointer_type_id_map()
|
||||
{return pointer_type_id_map_;}
|
||||
|
||||
string
|
||||
get_type_id_from_pointer(uintptr_t ptr) const
|
||||
{
|
||||
auto it = get_pointer_type_id_map().find(ptr);
|
||||
if (it != get_pointer_type_id_map().end())
|
||||
return it->second;
|
||||
return "";
|
||||
}
|
||||
|
||||
string
|
||||
get_type_id_from_type(const type_base *t) const
|
||||
{return get_type_id_from_pointer(reinterpret_cast<uintptr_t>(t));}
|
||||
|
||||
uintptr_t
|
||||
get_canonical_type_from_type_id(const char* type_id) const
|
||||
{
|
||||
if (!type_id)
|
||||
return 0;
|
||||
auto it = get_type_id_canonical_type_map().find(type_id);
|
||||
if (it != get_type_id_canonical_type_map().end())
|
||||
return it->second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// When debugging self comparison, verify that a type T
|
||||
/// de-serialized from abixml has the same canonical type as the
|
||||
/// initial type built from DWARF that was serialized into T in the
|
||||
@@ -1055,10 +1179,11 @@ struct environment::priv
|
||||
///
|
||||
/// @param t deserialized type (from abixml) to consider.
|
||||
///
|
||||
/// @param c the canonical type @p t should have.
|
||||
/// @param c the canonical type that @p t has, as computed freshly
|
||||
/// from the abixml file.
|
||||
///
|
||||
/// @return true iff @p c is the canonical type that @p t should
|
||||
/// have.
|
||||
/// @return true iff @p c has the same value as the canonical type
|
||||
/// that @p t had before being serialized into abixml.
|
||||
bool
|
||||
check_canonical_type_from_abixml_during_self_comp(const type_base* t,
|
||||
const type_base* c)
|
||||
@@ -1105,6 +1230,45 @@ struct environment::priv
|
||||
return false;
|
||||
}
|
||||
|
||||
/// When debugging self comparison, verify that a type T
|
||||
/// de-serialized from abixml has the same canonical type as the
|
||||
/// initial type built from DWARF that was serialized into T in the
|
||||
/// first place.
|
||||
///
|
||||
/// @param t deserialized type (from abixml) to consider.
|
||||
///
|
||||
/// @return true iff @p c is the canonical type that @p t should
|
||||
/// have.
|
||||
bool
|
||||
check_abixml_canonical_type_propagation_during_self_comp(const type_base* t)
|
||||
{
|
||||
if (t->get_corpus()
|
||||
&& t->get_corpus()->get_origin() == ir::corpus::NATIVE_XML_ORIGIN)
|
||||
{
|
||||
type_base* c = t->get_naked_canonical_type();
|
||||
if (c && !check_canonical_type_from_abixml_during_self_comp(t, c))
|
||||
{
|
||||
string repr = t->get_pretty_representation(true, true);
|
||||
string type_id = get_type_id_from_type(t);
|
||||
std::cerr << "error: canonical type propagation error for '"
|
||||
<< repr
|
||||
<< "' of type-id: '"
|
||||
<< type_id
|
||||
<< "' / type: @"
|
||||
<< std::hex
|
||||
<< t
|
||||
<< "/ canon: @"
|
||||
<< c
|
||||
<< ", should have had canonical type: "
|
||||
<< std::hex
|
||||
<< get_canonical_type_from_type_id(type_id.c_str())
|
||||
<< "\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// When debugging self comparison, verify that a type T
|
||||
/// de-serialized from abixml has the same canonical type as the
|
||||
/// initial type built from DWARF that was serialized into T in the
|
||||
@@ -1125,6 +1289,71 @@ struct environment::priv
|
||||
#endif
|
||||
};// end struct environment::priv
|
||||
|
||||
/// Compute the canonical type for all the IR types of the system.
|
||||
///
|
||||
/// After invoking this function, the time it takes to compare two
|
||||
/// types of the IR is equivalent to the time it takes to compare
|
||||
/// their pointer value. That is faster than performing a structural
|
||||
/// (A.K.A. member-wise) comparison.
|
||||
///
|
||||
/// Note that this function performs some sanity checks after* the
|
||||
/// canonicalization process. It ensures that at the end of the
|
||||
/// canonicalization process, all types have been canonicalized. This
|
||||
/// is important because the canonicalization algorithm sometimes
|
||||
/// clears some canonical types after having speculatively set them
|
||||
/// for performance purposes. At the end of the process however, all
|
||||
/// types must be canonicalized, and this function detects violations
|
||||
/// of that assertion.
|
||||
///
|
||||
/// @tparam input_iterator the type of the input iterator of the @p
|
||||
/// beging and @p end.
|
||||
///
|
||||
/// @tparam deref_lambda a lambda function which takes in parameter
|
||||
/// the input iterator of type @p input_iterator and dereferences it
|
||||
/// to return the type to canonicalize.
|
||||
///
|
||||
/// @param begin an iterator pointing to the first type of the set of types
|
||||
/// to canonicalize.
|
||||
///
|
||||
/// @param end an iterator pointing to the end (after the last type) of
|
||||
/// the set of types to canonicalize.
|
||||
///
|
||||
/// @param deref a lambda function that knows how to dereference the
|
||||
/// iterator @p begin to return the type to canonicalize.
|
||||
template<typename input_iterator,
|
||||
typename deref_lambda>
|
||||
void
|
||||
canonicalize_types(const input_iterator& begin,
|
||||
const input_iterator& end,
|
||||
deref_lambda deref)
|
||||
{
|
||||
if (begin == end)
|
||||
return;
|
||||
|
||||
int i;
|
||||
input_iterator t;
|
||||
// First, let's compute the canonical type of this type.
|
||||
for (t = begin,i = 0; t != end; ++t, ++i)
|
||||
{
|
||||
if (deref(t)->get_environment().priv_->do_log())
|
||||
std::cerr << "#" << std::dec << i << " ";
|
||||
|
||||
canonicalize(deref(t));
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_CT_PROPAGATION
|
||||
// Then now, make sure that all types -- which propagated canonical
|
||||
// type has been cleared -- have been canonicalized. In other
|
||||
// words, the set of types which have been recorded because their
|
||||
// propagated canonical type has been cleared must be empty.
|
||||
const environment& env = deref(begin)->get_environment();
|
||||
pointer_set to_canonicalize =
|
||||
env.priv_->types_with_cleared_propagated_ct();
|
||||
|
||||
ABG_ASSERT(to_canonicalize.empty());
|
||||
#endif // WITH_DEBUG_CT_PROPAGATION
|
||||
}
|
||||
|
||||
// <class_or_union::priv definitions>
|
||||
struct class_or_union::priv
|
||||
{
|
||||
@@ -1174,9 +1403,9 @@ struct class_or_union::priv
|
||||
const class_or_union& second) const
|
||||
{
|
||||
const environment& env = first.get_environment();
|
||||
env.priv_->classes_being_compared_.insert
|
||||
(std::make_pair(reinterpret_cast<uint64_t>(&first),
|
||||
reinterpret_cast<uint64_t>(&second)));
|
||||
|
||||
env.priv_->left_classes_being_compared_.insert(&first);
|
||||
env.priv_->right_classes_being_compared_.insert(&second);
|
||||
}
|
||||
|
||||
/// Mark a pair of classes or unions as being currently compared
|
||||
@@ -1236,9 +1465,9 @@ struct class_or_union::priv
|
||||
const class_or_union& second) const
|
||||
{
|
||||
const environment& env = first.get_environment();
|
||||
env.priv_->classes_being_compared_.erase
|
||||
(std::make_pair(reinterpret_cast<uint64_t>(&first),
|
||||
reinterpret_cast<uint64_t>(&second)));
|
||||
|
||||
env.priv_->left_classes_being_compared_.erase(&first);
|
||||
env.priv_->right_classes_being_compared_.erase(&second);
|
||||
}
|
||||
|
||||
/// If a pair of class_or_union has been previously marked as
|
||||
@@ -1277,10 +1506,11 @@ struct class_or_union::priv
|
||||
const class_or_union& second) const
|
||||
{
|
||||
const environment& env = first.get_environment();
|
||||
return env.priv_->
|
||||
classes_being_compared_.count
|
||||
(std::make_pair(reinterpret_cast<uint64_t>(&first),
|
||||
reinterpret_cast<uint64_t>((&second))));
|
||||
|
||||
return (env.priv_->left_classes_being_compared_.count(&first)
|
||||
|| env.priv_->right_classes_being_compared_.count(&second)
|
||||
|| env.priv_->right_classes_being_compared_.count(&first)
|
||||
|| env.priv_->left_classes_being_compared_.count(&second));
|
||||
}
|
||||
|
||||
/// Test if a pair of class_or_union is being currently compared.
|
||||
@@ -1337,9 +1567,9 @@ struct function_type::priv
|
||||
const function_type& second) const
|
||||
{
|
||||
const environment& env = first.get_environment();
|
||||
env.priv_->fn_types_being_compared_.insert
|
||||
(std::make_pair(reinterpret_cast<uint64_t>(&first),
|
||||
reinterpret_cast<uint64_t>(&second)));
|
||||
|
||||
env.priv_->left_fn_types_being_compared_.insert(&first);
|
||||
env.priv_->right_fn_types_being_compared_.insert(&second);
|
||||
}
|
||||
|
||||
/// Mark a given pair of @ref function_type as being compared.
|
||||
@@ -1354,9 +1584,9 @@ struct function_type::priv
|
||||
const function_type& second) const
|
||||
{
|
||||
const environment& env = first.get_environment();
|
||||
env.priv_->fn_types_being_compared_.erase
|
||||
(std::make_pair(reinterpret_cast<uint64_t>(&first),
|
||||
reinterpret_cast<uint64_t>(&second)));
|
||||
|
||||
env.priv_->left_fn_types_being_compared_.erase(&first);
|
||||
env.priv_->right_fn_types_being_compared_.erase(&second);
|
||||
}
|
||||
|
||||
/// Tests if a @ref function_type is currently being compared.
|
||||
@@ -1369,9 +1599,10 @@ struct function_type::priv
|
||||
const function_type& second) const
|
||||
{
|
||||
const environment& env = first.get_environment();
|
||||
return env.priv_->fn_types_being_compared_.count
|
||||
(std::make_pair(reinterpret_cast<uint64_t>(&first),
|
||||
reinterpret_cast<uint64_t>(&second)));
|
||||
|
||||
return (env.priv_->left_fn_types_being_compared_.count(&first)
|
||||
||
|
||||
env.priv_->right_fn_types_being_compared_.count(&second));
|
||||
}
|
||||
};// end struc function_type::priv
|
||||
|
||||
|
||||
+1694
-283
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) 2017-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2017-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -140,6 +140,9 @@ report_type_changes_from_diff_maps(const leaf_reporter& reporter,
|
||||
// typedefs
|
||||
report_diffs(reporter, maps.get_typedef_diff_map(), out, indent);
|
||||
|
||||
// subranges
|
||||
report_diffs(reporter, maps.get_subrange_diff_map(), out, indent);
|
||||
|
||||
// arrays
|
||||
report_diffs(reporter, maps.get_array_diff_map(), out, indent);
|
||||
|
||||
@@ -207,6 +210,12 @@ leaf_reporter::report(const qualified_type_diff& d, ostream& out,
|
||||
return;
|
||||
|
||||
report_local_qualified_type_changes(d, out, indent);
|
||||
|
||||
// Note that changes that are local to the underlying type of a
|
||||
// qualified type are considered to be local to the qualified type
|
||||
// itself. So let's go ahead and report the local changes of the
|
||||
// underlying type.
|
||||
report_underlying_changes_of_qualified_type(d, out, indent);
|
||||
}
|
||||
|
||||
/// Report the changes carried by a @ref pointer_diff node.
|
||||
@@ -430,6 +439,30 @@ leaf_reporter::report(const scope_diff& d,
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
/// Report about the change carried by a @ref subrange_diff diff node
|
||||
/// in a serialized form.
|
||||
///
|
||||
/// @param d the diff node to consider.
|
||||
///
|
||||
/// @param out the output stream to report to.
|
||||
///
|
||||
/// @param indent the indentation string to use in the report.
|
||||
void
|
||||
leaf_reporter::report(const subrange_diff& d, std::ostream& out,
|
||||
const std::string& indent) const
|
||||
{
|
||||
if (!diff_to_be_reported(&d))
|
||||
return;
|
||||
|
||||
RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3(d.first_subrange(),
|
||||
d.second_subrange(),
|
||||
"range type");
|
||||
|
||||
represent(d, d.context(), out,indent, /*local_only=*/true);
|
||||
|
||||
maybe_report_interfaces_impacted_by_diff(&d, out, indent);
|
||||
}
|
||||
|
||||
/// Report the changes carried by a @ref array_diff node.
|
||||
///
|
||||
/// @param out the output stream to report to.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
|
||||
|
||||
+334
-124
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
///
|
||||
@@ -62,8 +62,8 @@ static bool read_is_artificial(xmlNodePtr, bool&);
|
||||
static bool read_tracking_non_reachable_types(xmlNodePtr, bool&);
|
||||
static bool read_is_non_reachable_type(xmlNodePtr, bool&);
|
||||
static bool read_naming_typedef_id_string(xmlNodePtr, string&);
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
static bool read_type_id_string(xmlNodePtr, string&);
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
static bool maybe_map_type_with_type_id(const type_base_sptr&,
|
||||
xmlNodePtr);
|
||||
static bool maybe_map_type_with_type_id(const type_base_sptr&,
|
||||
@@ -98,6 +98,12 @@ read_symbol_db_from_input(reader& rdr,
|
||||
static translation_unit_sptr
|
||||
read_translation_unit_from_input(fe_iface& rdr);
|
||||
|
||||
static decl_base_sptr
|
||||
build_ir_node_for_void_type(reader& rdr);
|
||||
|
||||
static decl_base_sptr
|
||||
build_ir_node_for_void_pointer_type(reader& rdr);
|
||||
|
||||
/// The ABIXML reader object.
|
||||
///
|
||||
/// This abstracts the context in which the current ABI
|
||||
@@ -109,6 +115,9 @@ class reader : public fe_iface
|
||||
{
|
||||
public:
|
||||
|
||||
typedef unordered_map<string, vector<type_base_sptr> >
|
||||
types_map_type;
|
||||
|
||||
typedef unordered_map<string,
|
||||
vector<type_base_sptr> >::const_iterator
|
||||
const_types_map_it;
|
||||
@@ -136,7 +145,7 @@ public:
|
||||
get_artifact_used_by_relation_map(reader& rdr);
|
||||
|
||||
private:
|
||||
unordered_map<string, vector<type_base_sptr> > m_types_map;
|
||||
types_map_type m_types_map;
|
||||
unordered_map<string, shared_ptr<function_tdecl> > m_fn_tmpl_map;
|
||||
unordered_map<string, shared_ptr<class_tdecl> > m_class_tmpl_map;
|
||||
vector<type_base_sptr> m_types_to_canonicalize;
|
||||
@@ -165,6 +174,13 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// Test if logging was requested.
|
||||
///
|
||||
/// @return true iff logging was requested.
|
||||
bool
|
||||
do_log() const
|
||||
{return options().do_log;}
|
||||
|
||||
/// Getter for the flag that tells us if we are tracking types that
|
||||
/// are not reachable from global functions and variables.
|
||||
///
|
||||
@@ -328,6 +344,12 @@ public:
|
||||
get_scope_for_node(xmlNodePtr node,
|
||||
access_specifier& access);
|
||||
|
||||
scope_decl_sptr
|
||||
get_scope_for_node(xmlNodePtr node);
|
||||
|
||||
scope_decl*
|
||||
get_scope_ptr_for_node(xmlNodePtr node);
|
||||
|
||||
// This is defined later, after build_type() is declared, because it
|
||||
// uses it.
|
||||
type_base_sptr
|
||||
@@ -571,7 +593,7 @@ public:
|
||||
|
||||
/// Associate an ID with a type.
|
||||
///
|
||||
/// @param type the type to associate witht he ID.
|
||||
/// @param type the type to associate with the ID.
|
||||
///
|
||||
/// @param id the ID to associate to the type.
|
||||
///
|
||||
@@ -721,19 +743,34 @@ public:
|
||||
{record_artifacts_as_used_in_fn_type(fn_type.get());}
|
||||
#endif
|
||||
|
||||
/// This function must be called on each declaration that is created
|
||||
/// during the parsing. It adds the declaration to the scope that
|
||||
/// its XML node belongs to and updates the state of the parsing
|
||||
/// context accordingly.
|
||||
///
|
||||
/// @param decl the newly created declaration.
|
||||
///
|
||||
/// @param node the xml node @p decl originated from.
|
||||
void
|
||||
push_decl_to_scope(const decl_base_sptr& decl, xmlNodePtr node)
|
||||
{
|
||||
scope_decl* scope = nullptr;
|
||||
scope = get_scope_ptr_for_node(node);
|
||||
return push_decl_to_scope(decl, scope);
|
||||
}
|
||||
|
||||
/// This function must be called on each declaration that is created during
|
||||
/// the parsing. It adds the declaration to the current scope, and updates
|
||||
/// the state of the parsing context accordingly.
|
||||
///
|
||||
/// @param decl the newly created declaration.
|
||||
void
|
||||
push_decl_to_current_scope(decl_base_sptr decl,
|
||||
bool add_to_current_scope)
|
||||
push_decl_to_scope(const decl_base_sptr& decl,
|
||||
scope_decl* scope)
|
||||
{
|
||||
ABG_ASSERT(decl);
|
||||
|
||||
if (add_to_current_scope)
|
||||
add_decl_to_scope(decl, get_cur_scope());
|
||||
if (scope)
|
||||
add_decl_to_scope(decl, scope);
|
||||
if (!decl->get_translation_unit())
|
||||
decl->set_translation_unit(get_translation_unit());
|
||||
ABG_ASSERT(decl->get_translation_unit());
|
||||
@@ -748,16 +785,19 @@ public:
|
||||
///
|
||||
/// @param id the unique ID to be associated to t
|
||||
///
|
||||
/// @param scope the scope to add the type to.
|
||||
///
|
||||
/// @return true upon successful completion.
|
||||
///
|
||||
bool
|
||||
push_and_key_type_decl(shared_ptr<type_base> t, const string& id,
|
||||
bool add_to_current_scope)
|
||||
push_and_key_type_decl(const type_base_sptr& t,
|
||||
const string& id,
|
||||
scope_decl* scope)
|
||||
{
|
||||
shared_ptr<decl_base> decl = dynamic_pointer_cast<decl_base>(t);
|
||||
decl_base_sptr decl = get_type_declaration(t);
|
||||
ABG_ASSERT(decl);
|
||||
|
||||
push_decl_to_current_scope(decl, add_to_current_scope);
|
||||
push_decl_to_scope(decl, scope);
|
||||
if (!t->get_translation_unit())
|
||||
t->set_translation_unit(get_translation_unit());
|
||||
ABG_ASSERT(t->get_translation_unit());
|
||||
@@ -765,6 +805,31 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
/// This function must be called on each type decl that is created
|
||||
/// during the parsing. It adds the type decl to the current scope
|
||||
/// and associates a unique ID to it.
|
||||
///
|
||||
/// @param t the type to consider.
|
||||
///
|
||||
/// @param node the XML it originates from.
|
||||
///
|
||||
/// @return true upon successful completion.
|
||||
///
|
||||
bool
|
||||
push_and_key_type_decl(const type_base_sptr& t,
|
||||
const xmlNodePtr node,
|
||||
bool add_to_current_scope)
|
||||
{
|
||||
string id;
|
||||
if (!read_type_id_string(node, id))
|
||||
return false;
|
||||
|
||||
scope_decl* scope = nullptr;
|
||||
if (add_to_current_scope && !is_unique_type(t))
|
||||
scope = get_scope_ptr_for_node(node);
|
||||
return push_and_key_type_decl(t, id, scope);
|
||||
}
|
||||
|
||||
/// Getter for the object that determines if a given declaration
|
||||
/// ought to be put in the set of exported decls of the current
|
||||
/// corpus.
|
||||
@@ -844,8 +909,8 @@ public:
|
||||
void
|
||||
maybe_check_abixml_canonical_type_stability(type_base_sptr& t)
|
||||
{
|
||||
if (!get_environment()->self_comparison_debug_is_on()
|
||||
|| get_environment()->get_type_id_canonical_type_map().empty())
|
||||
if (!get_environment().self_comparison_debug_is_on()
|
||||
|| get_environment().get_type_id_canonical_type_map().empty())
|
||||
return ;
|
||||
|
||||
if (class_decl_sptr c = is_class_type(t))
|
||||
@@ -857,15 +922,15 @@ public:
|
||||
// Let's get the type-id of this type as recorded in the
|
||||
// originating abixml file.
|
||||
string type_id =
|
||||
get_environment()->get_type_id_from_pointer(reinterpret_cast<uintptr_t>(t.get()));
|
||||
get_environment().get_type_id_from_pointer(reinterpret_cast<uintptr_t>(t.get()));
|
||||
|
||||
if (!type_id.empty())
|
||||
{
|
||||
// Now let's get the canonical type that initially led to the
|
||||
// serialization of a type with this type-id, when the abixml
|
||||
// was being serialized.
|
||||
auto j = get_environment()->get_type_id_canonical_type_map().find(type_id);
|
||||
if (j == get_environment()->get_type_id_canonical_type_map().end())
|
||||
auto j = get_environment().get_type_id_canonical_type_map().find(type_id);
|
||||
if (j == get_environment().get_type_id_canonical_type_map().end())
|
||||
{
|
||||
if (t->get_naked_canonical_type())
|
||||
std::cerr << "error: no type with type-id: '"
|
||||
@@ -874,13 +939,13 @@ public:
|
||||
}
|
||||
else if (j->second
|
||||
!= reinterpret_cast<uintptr_t>(t->get_canonical_type().get()))
|
||||
// So thecanonical type of 't' (at abixml de-serialization
|
||||
// So the canonical type of 't' (at abixml de-serialization
|
||||
// time) is different from the canonical type that led to
|
||||
// the serialization of 't' at abixml serialization time.
|
||||
// Report this because it needs further debugging.
|
||||
std::cerr << "error: canonical type for type '"
|
||||
<< t->get_pretty_representation(/*internal=*/false,
|
||||
/*qualified=*/false)
|
||||
<< t->get_pretty_representation(/*internal=*/true,
|
||||
/*qualified=*/true)
|
||||
<< "' of type-id '" << type_id
|
||||
<< "' changed from '" << std::hex
|
||||
<< j->second << "' to '" << std::hex
|
||||
@@ -1100,9 +1165,8 @@ public:
|
||||
return nil;
|
||||
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
if (get_environment()->self_comparison_debug_is_on())
|
||||
get_environment()->
|
||||
set_self_comparison_debug_input(corpus());
|
||||
if (get_environment().self_comparison_debug_is_on())
|
||||
get_environment().set_self_comparison_debug_input(corpus());
|
||||
#endif
|
||||
|
||||
if (!corpus_group())
|
||||
@@ -1161,9 +1225,8 @@ public:
|
||||
else
|
||||
{
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
if (get_environment()->self_comparison_debug_is_on())
|
||||
get_environment()->
|
||||
set_self_comparison_debug_input(corpus());
|
||||
if (get_environment().self_comparison_debug_is_on())
|
||||
get_environment().set_self_comparison_debug_input(corpus());
|
||||
#endif
|
||||
|
||||
if (!corpus_group())
|
||||
@@ -1233,8 +1296,23 @@ public:
|
||||
}
|
||||
|
||||
|
||||
tools_utils::timer t;
|
||||
if (do_log())
|
||||
{
|
||||
std::cerr << "perform late type canonicalization ...\n";
|
||||
t.start();
|
||||
}
|
||||
|
||||
perform_late_type_canonicalizing();
|
||||
|
||||
if (do_log())
|
||||
{
|
||||
t.stop();
|
||||
std::cerr << "late type canonicalization DONE@"
|
||||
<< corpus()->get_path()
|
||||
<< ":" << t << "\n";
|
||||
}
|
||||
|
||||
get_environment().canonicalization_is_done(true);
|
||||
|
||||
if (call_reader_next)
|
||||
@@ -1319,11 +1397,11 @@ build_function_parameter (reader&, const xmlNodePtr);
|
||||
|
||||
static function_decl_sptr
|
||||
build_function_decl(reader&, const xmlNodePtr,
|
||||
class_or_union_sptr, bool);
|
||||
class_or_union_sptr, bool, bool);
|
||||
|
||||
static function_decl_sptr
|
||||
build_function_decl_if_not_suppressed(reader&, const xmlNodePtr,
|
||||
class_or_union_sptr, bool);
|
||||
class_or_union_sptr, bool, bool);
|
||||
|
||||
static bool
|
||||
function_is_suppressed(const reader& rdr,
|
||||
@@ -1355,7 +1433,7 @@ static shared_ptr<function_type>
|
||||
build_function_type(reader&, const xmlNodePtr, bool);
|
||||
|
||||
static array_type_def::subrange_sptr
|
||||
build_subrange_type(reader&, const xmlNodePtr);
|
||||
build_subrange_type(reader&, const xmlNodePtr, bool);
|
||||
|
||||
static array_type_def_sptr
|
||||
build_array_type_def(reader&, const xmlNodePtr, bool);
|
||||
@@ -1455,8 +1533,7 @@ static decl_base_sptr handle_class_tdecl(reader&, xmlNodePtr, bool);
|
||||
/// @return the IR node representing the scope of the IR node for the
|
||||
/// XML node given in argument.
|
||||
scope_decl_sptr
|
||||
reader::get_scope_for_node(xmlNodePtr node,
|
||||
access_specifier& access)
|
||||
reader::get_scope_for_node(xmlNodePtr node, access_specifier& access)
|
||||
{
|
||||
scope_decl_sptr nil, scope;
|
||||
if (!node)
|
||||
@@ -1468,7 +1545,9 @@ reader::get_scope_for_node(xmlNodePtr node,
|
||||
&& (xmlStrEqual(parent->name, BAD_CAST("data-member"))
|
||||
|| xmlStrEqual(parent->name, BAD_CAST("member-type"))
|
||||
|| xmlStrEqual(parent->name, BAD_CAST("member-function"))
|
||||
|| xmlStrEqual(parent->name, BAD_CAST("member-template"))))
|
||||
|| xmlStrEqual(parent->name, BAD_CAST("member-template"))
|
||||
|| xmlStrEqual(parent->name, BAD_CAST("template-parameter-type-composition"))
|
||||
|| xmlStrEqual(parent->name, BAD_CAST("array-type-def"))))
|
||||
{
|
||||
read_access(parent, access);
|
||||
parent = parent->parent;
|
||||
@@ -1499,6 +1578,40 @@ reader::get_scope_for_node(xmlNodePtr node,
|
||||
return scope;
|
||||
}
|
||||
|
||||
/// Get the IR node representing the scope for a given XML node.
|
||||
///
|
||||
/// This function might trigger the building of a full sub-tree of IR.
|
||||
///
|
||||
/// @param node the XML for which to return the scope decl. If its
|
||||
/// parent XML node has no corresponding IR node, that IR node is constructed.
|
||||
///
|
||||
/// @return the IR node representing the scope of the IR node for the
|
||||
/// XML node given in argument.
|
||||
scope_decl_sptr
|
||||
reader::get_scope_for_node(xmlNodePtr node)
|
||||
{
|
||||
access_specifier access;
|
||||
return get_scope_for_node(node, access);
|
||||
}
|
||||
|
||||
/// Get the IR node representing the scope for a given XML node.
|
||||
///
|
||||
/// This function might trigger the building of a full sub-tree of IR.
|
||||
///
|
||||
/// @param node the XML for which to return the scope decl. If its
|
||||
/// parent XML node has no corresponding IR node, that IR node is constructed.
|
||||
///
|
||||
/// @return the IR node representing the scope of the IR node for the
|
||||
/// XML node given in argument.
|
||||
scope_decl*
|
||||
reader::get_scope_ptr_for_node(xmlNodePtr node)
|
||||
{
|
||||
scope_decl_sptr scope = get_scope_for_node(node);
|
||||
if (scope)
|
||||
return scope.get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Get the type declaration IR node that matches a given XML type node ID.
|
||||
///
|
||||
/// If no IR node has been built for this ID, this function builds the
|
||||
@@ -1509,8 +1622,7 @@ reader::get_scope_for_node(xmlNodePtr node,
|
||||
///
|
||||
/// @return the type declaration for the ID given in parameter.
|
||||
type_base_sptr
|
||||
reader::build_or_get_type_decl(const string& id,
|
||||
bool add_decl_to_scope)
|
||||
reader::build_or_get_type_decl(const string& id, bool add_decl_to_scope)
|
||||
{
|
||||
type_base_sptr t = get_type_decl(id);
|
||||
|
||||
@@ -2861,8 +2973,6 @@ read_elf_symbol_visibility(xmlNodePtr node, elf_symbol::visibility& v)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
/// Read the value of the 'id' attribute from a given XML node.
|
||||
///
|
||||
/// @param node the XML node to consider.
|
||||
@@ -2881,6 +2991,7 @@ read_type_id_string(xmlNodePtr node, string& type_id)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
/// Associate a type-id string with the type that was constructed from
|
||||
/// it.
|
||||
///
|
||||
@@ -2906,8 +3017,8 @@ maybe_map_type_with_type_id(const type_base_sptr& t,
|
||||
|| is_non_canonicalized_type(t.get()))
|
||||
return false;
|
||||
|
||||
env.get_pointer_type_id_map()[reinterpret_cast<uintptr_t>(t.get())] =
|
||||
type_id;
|
||||
const_cast<environment&>(env).
|
||||
get_pointer_type_id_map()[reinterpret_cast<uintptr_t>(t.get())] = type_id;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -3011,7 +3122,10 @@ build_namespace_decl(reader& rdr,
|
||||
const environment& env = rdr.get_environment();
|
||||
namespace_decl_sptr decl(new namespace_decl(env, name, loc));
|
||||
maybe_set_artificial_location(rdr, node, decl);
|
||||
rdr.push_decl_to_current_scope(decl, add_to_current_scope);
|
||||
rdr.push_decl_to_scope(decl,
|
||||
add_to_current_scope
|
||||
? rdr.get_scope_ptr_for_node(node)
|
||||
: nullptr);
|
||||
rdr.map_xml_node_to_decl(node, decl);
|
||||
|
||||
for (xmlNodePtr n = xmlFirstElementChild(node);
|
||||
@@ -3158,12 +3272,15 @@ build_elf_symbol_from_reference(reader& rdr, const xmlNodePtr node)
|
||||
if (name.empty())
|
||||
return nil;
|
||||
|
||||
const elf_symbols& symbols =
|
||||
rdr.corpus()->get_symtab()->lookup_symbol(name);
|
||||
if (rdr.corpus()->get_symtab())
|
||||
{
|
||||
const elf_symbols& symbols =
|
||||
rdr.corpus()->get_symtab()->lookup_symbol(name);
|
||||
|
||||
for (const auto& symbol : symbols)
|
||||
if (symbol->get_id_string() == sym_id)
|
||||
return symbol;
|
||||
for (const auto& symbol : symbols)
|
||||
if (symbol->get_id_string() == sym_id)
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
@@ -3323,16 +3440,21 @@ build_function_parameter(reader& rdr, const xmlNodePtr node)
|
||||
/// shared_ptr<function_decl> that is returned is then really a
|
||||
/// shared_ptr<method_decl>.
|
||||
///
|
||||
/// @param add_to_current_scope if set to yes, the resulting of
|
||||
/// @param add_to_current_scope if set to yes, the result of
|
||||
/// this function is added to its current scope.
|
||||
///
|
||||
/// @param add_to_exported_decls if set to yes, the resulting of this
|
||||
/// function is added to the set of decls exported by the current
|
||||
/// corpus being built.
|
||||
///
|
||||
/// @return a pointer to a newly created function_decl upon successful
|
||||
/// completion, a null pointer otherwise.
|
||||
static function_decl_sptr
|
||||
build_function_decl(reader& rdr,
|
||||
build_function_decl(reader& rdr,
|
||||
const xmlNodePtr node,
|
||||
class_or_union_sptr as_method_decl,
|
||||
bool add_to_current_scope)
|
||||
bool add_to_current_scope,
|
||||
bool add_to_exported_decls)
|
||||
{
|
||||
function_decl_sptr nil;
|
||||
|
||||
@@ -3347,6 +3469,16 @@ build_function_decl(reader& rdr,
|
||||
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "mangled-name"))
|
||||
mangled_name = xml::unescape_xml_string(CHAR_STR(s));
|
||||
|
||||
if (as_method_decl
|
||||
&& !mangled_name.empty()
|
||||
&& as_method_decl->find_member_function_sptr(mangled_name))
|
||||
{
|
||||
function_decl_sptr result =
|
||||
as_method_decl->find_member_function_sptr(mangled_name);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
string inline_prop;
|
||||
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "declared-inline"))
|
||||
inline_prop = CHAR_STR(s);
|
||||
@@ -3411,7 +3543,10 @@ build_function_decl(reader& rdr,
|
||||
bind));
|
||||
|
||||
maybe_set_artificial_location(rdr, node, fn_decl);
|
||||
rdr.push_decl_to_current_scope(fn_decl, add_to_current_scope);
|
||||
rdr.push_decl_to_scope(fn_decl,
|
||||
add_to_current_scope
|
||||
? rdr.get_scope_ptr_for_node(node)
|
||||
: nullptr);
|
||||
RECORD_ARTIFACTS_AS_USED_IN_FN_DECL(rdr, fn_decl);
|
||||
|
||||
elf_symbol_sptr sym = build_elf_symbol_from_reference(rdr, node);
|
||||
@@ -3425,7 +3560,8 @@ build_function_decl(reader& rdr,
|
||||
|
||||
rdr.maybe_canonicalize_type(fn_type, !add_to_current_scope);
|
||||
|
||||
rdr.maybe_add_fn_to_exported_decls(fn_decl.get());
|
||||
if (add_to_exported_decls)
|
||||
rdr.maybe_add_fn_to_exported_decls(fn_decl.get());
|
||||
|
||||
return fn_decl;
|
||||
}
|
||||
@@ -3448,16 +3584,21 @@ build_function_decl(reader& rdr,
|
||||
/// @param add_to_current_scope if set to yes, the resulting of
|
||||
/// this function is added to its current scope.
|
||||
///
|
||||
/// @param add_to_exported_decls if set to yes, the resulting of this
|
||||
/// function is added to the set of decls exported by the current
|
||||
/// corpus being built.
|
||||
///
|
||||
/// @return a pointer to a newly created function_decl upon successful
|
||||
/// completion. If the function was suppressed by a suppression
|
||||
/// specification then returns nil.
|
||||
static function_decl_sptr
|
||||
build_function_decl_if_not_suppressed(reader& rdr,
|
||||
const xmlNodePtr node,
|
||||
class_or_union_sptr as_method_decl,
|
||||
bool add_to_current_scope)
|
||||
build_function_decl_if_not_suppressed(reader& rdr,
|
||||
const xmlNodePtr node,
|
||||
class_or_union_sptr as_method_decl,
|
||||
bool add_to_current_scope,
|
||||
bool add_to_exported_decls)
|
||||
{
|
||||
function_decl_sptr fn;
|
||||
function_decl_sptr fn;
|
||||
|
||||
if (function_is_suppressed(rdr, node))
|
||||
// The function was suppressed by at least one suppression
|
||||
@@ -3466,7 +3607,8 @@ build_function_decl_if_not_suppressed(reader& rdr,
|
||||
;
|
||||
else
|
||||
fn = build_function_decl(rdr, node, as_method_decl,
|
||||
add_to_current_scope);
|
||||
add_to_current_scope,
|
||||
add_to_exported_decls);
|
||||
return fn;
|
||||
}
|
||||
|
||||
@@ -3650,7 +3792,10 @@ build_var_decl(reader& rdr,
|
||||
if (sym)
|
||||
decl->set_symbol(sym);
|
||||
|
||||
rdr.push_decl_to_current_scope(decl, add_to_current_scope);
|
||||
rdr.push_decl_to_scope(decl,
|
||||
add_to_current_scope
|
||||
? rdr.get_scope_ptr_for_node(node)
|
||||
: nullptr);
|
||||
if (add_to_current_scope)
|
||||
{
|
||||
// This variable is really being kept in the IR, so let's record
|
||||
@@ -3664,6 +3809,46 @@ build_var_decl(reader& rdr,
|
||||
return decl;
|
||||
}
|
||||
|
||||
/// Build the IR node for a void type.
|
||||
///
|
||||
/// @param rdr the ABIXML reader to use.
|
||||
///
|
||||
/// @return the void type node.
|
||||
static decl_base_sptr
|
||||
build_ir_node_for_void_type(reader& rdr)
|
||||
{
|
||||
const environment& env = rdr.get_environment();
|
||||
|
||||
type_base_sptr t = env.get_void_type();
|
||||
add_decl_to_scope(is_decl(t), rdr.get_translation_unit()->get_global_scope());
|
||||
decl_base_sptr type_declaration = get_type_declaration(t);
|
||||
canonicalize(t);
|
||||
return type_declaration;
|
||||
}
|
||||
|
||||
/// Build the IR node for a "pointer to void type".
|
||||
///
|
||||
/// That IR node is shared across the ABI corpus.
|
||||
///
|
||||
/// Note that this function just gets that IR node from the
|
||||
/// environment and, if it's not added to any scope yet, adds it to
|
||||
/// the global scope associated to the current translation unit.
|
||||
///
|
||||
/// @param rdr the DWARF reader to consider.
|
||||
///
|
||||
/// @return the IR node.
|
||||
static decl_base_sptr
|
||||
build_ir_node_for_void_pointer_type(reader& rdr)
|
||||
{
|
||||
const environment& env = rdr.get_environment();
|
||||
|
||||
type_base_sptr t = env.get_void_pointer_type();
|
||||
add_decl_to_scope(is_decl(t), rdr.get_translation_unit()->get_global_scope());
|
||||
decl_base_sptr type_declaration = get_type_declaration(t);
|
||||
canonicalize(t);
|
||||
return type_declaration;
|
||||
}
|
||||
|
||||
/// Build a type_decl from a "type-decl" XML Node.
|
||||
///
|
||||
/// @param rdr the context of the parsing.
|
||||
@@ -3675,7 +3860,7 @@ build_var_decl(reader& rdr,
|
||||
///
|
||||
/// @return a pointer to type_decl upon successful completion, a null
|
||||
/// pointer otherwise.
|
||||
static shared_ptr<type_decl>
|
||||
static type_decl_sptr
|
||||
build_type_decl(reader& rdr,
|
||||
const xmlNodePtr node,
|
||||
bool add_to_current_scope)
|
||||
@@ -3732,12 +3917,18 @@ build_type_decl(reader& rdr,
|
||||
}
|
||||
|
||||
const environment& env = rdr.get_environment();
|
||||
type_decl_sptr decl(new type_decl(env, name, size_in_bits,
|
||||
alignment_in_bits, loc));
|
||||
type_decl_sptr decl;
|
||||
if (name == env.get_variadic_parameter_type_name())
|
||||
decl = is_type_decl(env.get_variadic_parameter_type());
|
||||
else if (name == "void")
|
||||
decl = is_type_decl(build_ir_node_for_void_type(rdr));
|
||||
else
|
||||
decl.reset(new type_decl(env, name, size_in_bits,
|
||||
alignment_in_bits, loc));
|
||||
maybe_set_artificial_location(rdr, node, decl);
|
||||
decl->set_is_anonymous(is_anonymous);
|
||||
decl->set_is_declaration_only(is_decl_only);
|
||||
if (rdr.push_and_key_type_decl(decl, id, add_to_current_scope))
|
||||
if (rdr.push_and_key_type_decl(decl, node, add_to_current_scope))
|
||||
{
|
||||
rdr.map_xml_node_to_decl(node, decl);
|
||||
return decl;
|
||||
@@ -3825,7 +4016,7 @@ build_qualified_type_decl(reader& rdr,
|
||||
{
|
||||
decl.reset(new qualified_type_def(underlying_type, cv, loc));
|
||||
maybe_set_artificial_location(rdr, node, decl);
|
||||
rdr.push_and_key_type_decl(decl, id, add_to_current_scope);
|
||||
rdr.push_and_key_type_decl(decl, node, add_to_current_scope);
|
||||
RECORD_ARTIFACT_AS_USED_BY(rdr, underlying_type, decl);
|
||||
}
|
||||
|
||||
@@ -3886,25 +4077,29 @@ build_pointer_type_def(reader& rdr,
|
||||
location loc;
|
||||
read_location(rdr, node, loc);
|
||||
|
||||
// Create the pointer type /before/ the pointed-to type. After the
|
||||
// creation, the type is 'keyed' using rdr.push_and_key_type_decl.
|
||||
// This means that the type can be retrieved from its type ID. This
|
||||
// is so that if the pointed-to type indirectly uses this pointer
|
||||
// type (via recursion) then that is made possible.
|
||||
pointer_type_def_sptr t(new pointer_type_def(rdr.get_environment(),
|
||||
size_in_bits,
|
||||
alignment_in_bits,
|
||||
loc));
|
||||
maybe_set_artificial_location(rdr, node, t);
|
||||
|
||||
if (rdr.push_and_key_type_decl(t, id, add_to_current_scope))
|
||||
rdr.map_xml_node_to_decl(node, t);
|
||||
|
||||
type_base_sptr pointed_to_type =
|
||||
rdr.build_or_get_type_decl(type_id, true);
|
||||
ABG_ASSERT(pointed_to_type);
|
||||
|
||||
t->set_pointed_to_type(pointed_to_type);
|
||||
pointer_type_def_sptr t;
|
||||
if (rdr.get_environment().is_void_type(pointed_to_type))
|
||||
t = is_pointer_type(build_ir_node_for_void_pointer_type(rdr));
|
||||
else
|
||||
// Create the pointer type /before/ the pointed-to type. After the
|
||||
// creation, the type is 'keyed' using rdr.push_and_key_type_decl.
|
||||
// This means that the type can be retrieved from its type ID. This
|
||||
// is so that if the pointed-to type indirectly uses this pointer
|
||||
// type (via recursion) then that is made possible.
|
||||
t.reset(new pointer_type_def(pointed_to_type,
|
||||
size_in_bits,
|
||||
alignment_in_bits,
|
||||
loc));
|
||||
|
||||
maybe_set_artificial_location(rdr, node, t);
|
||||
|
||||
if (rdr.push_and_key_type_decl(t, node, add_to_current_scope))
|
||||
rdr.map_xml_node_to_decl(node, t);
|
||||
|
||||
RECORD_ARTIFACT_AS_USED_BY(rdr, pointed_to_type, t);
|
||||
return t;
|
||||
}
|
||||
@@ -3977,7 +4172,7 @@ build_reference_type_def(reader& rdr,
|
||||
is_lvalue, size_in_bits,
|
||||
alignment_in_bits, loc));
|
||||
maybe_set_artificial_location(rdr, node, t);
|
||||
if (rdr.push_and_key_type_decl(t, id, add_to_current_scope))
|
||||
if (rdr.push_and_key_type_decl(t, node, add_to_current_scope))
|
||||
rdr.map_xml_node_to_decl(node, t);
|
||||
|
||||
type_base_sptr pointed_to_type =
|
||||
@@ -4034,16 +4229,16 @@ build_function_type(reader& rdr,
|
||||
{
|
||||
method_class_type =
|
||||
is_class_or_union_type(rdr.build_or_get_type_decl(method_class_id,
|
||||
/*add_decl_to_scope=*/true));
|
||||
/*add_decl_to_scope=*/true));
|
||||
ABG_ASSERT(method_class_type);
|
||||
}
|
||||
|
||||
function_type_sptr fn_type(is_method_t
|
||||
? new method_type(method_class_type,
|
||||
/*is_const=*/false,
|
||||
size, align)
|
||||
: new function_type(return_type,
|
||||
parms, size, align));
|
||||
function_type_sptr fn_type(is_method_t
|
||||
? new method_type(method_class_type,
|
||||
/*is_const=*/false,
|
||||
size, align)
|
||||
: new function_type(return_type,
|
||||
parms, size, align));
|
||||
|
||||
rdr.get_translation_unit()->bind_function_type_life_time(fn_type);
|
||||
rdr.key_type_decl(fn_type, id);
|
||||
@@ -4087,8 +4282,9 @@ build_function_type(reader& rdr,
|
||||
/// @return a pointer to a newly built array_type_def::subrange_type
|
||||
/// upon successful completion, a null pointer otherwise.
|
||||
static array_type_def::subrange_sptr
|
||||
build_subrange_type(reader& rdr,
|
||||
const xmlNodePtr node)
|
||||
build_subrange_type(reader& rdr,
|
||||
const xmlNodePtr node,
|
||||
bool add_to_current_scope)
|
||||
{
|
||||
array_type_def::subrange_sptr nil;
|
||||
|
||||
@@ -4128,7 +4324,7 @@ build_subrange_type(reader& rdr,
|
||||
bool is_infinite = false;
|
||||
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "length"))
|
||||
{
|
||||
if (string(CHAR_STR(s)) == "infinite")
|
||||
if (string(CHAR_STR(s)) == "infinite" || string(CHAR_STR(s)) == "unknown")
|
||||
is_infinite = true;
|
||||
else
|
||||
length = strtoull(CHAR_STR(s), NULL, 0);
|
||||
@@ -4187,6 +4383,9 @@ build_subrange_type(reader& rdr,
|
||||
maybe_set_artificial_location(rdr, node, p);
|
||||
p->is_infinite(is_infinite);
|
||||
|
||||
if (rdr.push_and_key_type_decl(p, node, add_to_current_scope))
|
||||
rdr.map_xml_node_to_decl(node, p);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -4259,7 +4458,8 @@ build_array_type_def(reader& rdr,
|
||||
size_in_bits = strtoull(CHAR_STR(s), &endptr, 0);
|
||||
if (*endptr != '\0')
|
||||
{
|
||||
if (!strcmp(CHAR_STR(s), "infinite"))
|
||||
if (!strcmp(CHAR_STR(s), "infinite")
|
||||
||!strcmp(CHAR_STR(s), "unknown"))
|
||||
size_in_bits = (size_t) -1;
|
||||
else
|
||||
return nil;
|
||||
@@ -4284,7 +4484,7 @@ build_array_type_def(reader& rdr,
|
||||
if (xmlStrEqual(n->name, BAD_CAST("subrange")))
|
||||
{
|
||||
if (array_type_def::subrange_sptr s =
|
||||
build_subrange_type(rdr, n))
|
||||
build_subrange_type(rdr, n, /*add_to_current_scope=*/true))
|
||||
{
|
||||
MAYBE_MAP_TYPE_WITH_TYPE_ID(s, n);
|
||||
if (add_to_current_scope)
|
||||
@@ -4303,7 +4503,7 @@ build_array_type_def(reader& rdr,
|
||||
|
||||
array_type_def_sptr ar_type(new array_type_def(type, subranges, loc));
|
||||
maybe_set_artificial_location(rdr, node, ar_type);
|
||||
if (rdr.push_and_key_type_decl(ar_type, id, add_to_current_scope))
|
||||
if (rdr.push_and_key_type_decl(ar_type, node, add_to_current_scope))
|
||||
rdr.map_xml_node_to_decl(node, ar_type);
|
||||
RECORD_ARTIFACT_AS_USED_BY(rdr, type, ar_type);
|
||||
|
||||
@@ -4479,7 +4679,7 @@ build_enum_type_decl(reader& rdr,
|
||||
t->set_is_anonymous(is_anonymous);
|
||||
t->set_is_artificial(is_artificial);
|
||||
t->set_is_declaration_only(is_decl_only);
|
||||
if (rdr.push_and_key_type_decl(t, id, add_to_current_scope))
|
||||
if (rdr.push_and_key_type_decl(t, node, add_to_current_scope))
|
||||
{
|
||||
maybe_set_naming_typedef(rdr, node, t);
|
||||
rdr.map_xml_node_to_decl(node, t);
|
||||
@@ -4520,13 +4720,6 @@ build_typedef_decl(reader& rdr,
|
||||
id = CHAR_STR(s);
|
||||
ABG_ASSERT(!id.empty());
|
||||
|
||||
if (type_base_sptr t = rdr.get_type_decl(id))
|
||||
{
|
||||
typedef_decl_sptr result = is_typedef(t);
|
||||
ABG_ASSERT(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
string name;
|
||||
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "name"))
|
||||
name = xml::unescape_xml_string(CHAR_STR(s));
|
||||
@@ -4544,7 +4737,7 @@ build_typedef_decl(reader& rdr,
|
||||
|
||||
typedef_decl_sptr t(new typedef_decl(name, underlying_type, loc));
|
||||
maybe_set_artificial_location(rdr, node, t);
|
||||
rdr.push_and_key_type_decl(t, id, add_to_current_scope);
|
||||
rdr.push_and_key_type_decl(t, node, add_to_current_scope);
|
||||
rdr.map_xml_node_to_decl(node, t);
|
||||
RECORD_ARTIFACT_AS_USED_BY(rdr, underlying_type, t);
|
||||
|
||||
@@ -4786,7 +4979,10 @@ build_class_decl(reader& rdr,
|
||||
|
||||
ABG_ASSERT(!is_decl_only || !is_def_of_decl);
|
||||
|
||||
rdr.push_decl_to_current_scope(decl, add_to_current_scope);
|
||||
rdr.push_decl_to_scope(decl,
|
||||
add_to_current_scope
|
||||
? rdr.get_scope_ptr_for_node(node)
|
||||
: nullptr);
|
||||
|
||||
rdr.map_xml_node_to_decl(node, decl);
|
||||
rdr.key_type_decl(decl, id);
|
||||
@@ -4795,7 +4991,7 @@ build_class_decl(reader& rdr,
|
||||
maybe_set_naming_typedef(rdr, node, decl);
|
||||
|
||||
for (xmlNodePtr n = xmlFirstElementChild(node);
|
||||
!is_decl_only && n;
|
||||
n;
|
||||
n = xmlNextElementSibling(n))
|
||||
{
|
||||
if (xmlStrEqual(n->name, BAD_CAST("base-class")))
|
||||
@@ -4930,8 +5126,6 @@ build_class_decl(reader& rdr,
|
||||
}
|
||||
else if (xmlStrEqual(n->name, BAD_CAST("member-function")))
|
||||
{
|
||||
rdr.map_xml_node_to_decl(n, decl);
|
||||
|
||||
access_specifier access =
|
||||
is_struct
|
||||
? public_access
|
||||
@@ -4959,7 +5153,8 @@ build_class_decl(reader& rdr,
|
||||
{
|
||||
if (function_decl_sptr f =
|
||||
build_function_decl_if_not_suppressed(rdr, p, decl,
|
||||
/*add_to_cur_sc=*/true))
|
||||
/*add_to_cur_sc=*/true,
|
||||
/*add_to_exported_decls=*/false))
|
||||
{
|
||||
method_decl_sptr m = is_method_decl(f);
|
||||
ABG_ASSERT(m);
|
||||
@@ -4971,6 +5166,8 @@ build_class_decl(reader& rdr,
|
||||
set_member_function_is_ctor(m, is_ctor);
|
||||
set_member_function_is_dtor(m, is_dtor);
|
||||
set_member_function_is_const(m, is_const);
|
||||
rdr.map_xml_node_to_decl(p, m);
|
||||
rdr.maybe_add_fn_to_exported_decls(f.get());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -5199,7 +5396,10 @@ build_union_decl(reader& rdr,
|
||||
|
||||
ABG_ASSERT(!is_decl_only || !is_def_of_decl);
|
||||
|
||||
rdr.push_decl_to_current_scope(decl, add_to_current_scope);
|
||||
rdr.push_decl_to_scope(decl,
|
||||
add_to_current_scope
|
||||
? rdr.get_scope_ptr_for_node(node)
|
||||
: nullptr);
|
||||
|
||||
rdr.map_xml_node_to_decl(node, decl);
|
||||
rdr.key_type_decl(decl, id);
|
||||
@@ -5312,7 +5512,8 @@ build_union_decl(reader& rdr,
|
||||
{
|
||||
if (function_decl_sptr f =
|
||||
build_function_decl_if_not_suppressed(rdr, p, decl,
|
||||
/*add_to_cur_sc=*/true))
|
||||
/*add_to_cur_sc=*/true,
|
||||
/*add_to_exported_decls=*/false))
|
||||
{
|
||||
method_decl_sptr m = is_method_decl(f);
|
||||
ABG_ASSERT(m);
|
||||
@@ -5321,6 +5522,7 @@ build_union_decl(reader& rdr,
|
||||
set_member_function_is_ctor(m, is_ctor);
|
||||
set_member_function_is_dtor(m, is_dtor);
|
||||
set_member_function_is_const(m, is_const);
|
||||
rdr.maybe_add_fn_to_exported_decls(f.get());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -5413,7 +5615,12 @@ build_function_tdecl(reader& rdr,
|
||||
function_tdecl_sptr fn_tmpl_decl(new function_tdecl(env, loc, vis, bind));
|
||||
maybe_set_artificial_location(rdr, node, fn_tmpl_decl);
|
||||
|
||||
rdr.push_decl_to_current_scope(fn_tmpl_decl, add_to_current_scope);
|
||||
rdr.push_decl_to_scope(fn_tmpl_decl,
|
||||
add_to_current_scope
|
||||
? rdr.get_scope_ptr_for_node(node)
|
||||
: nullptr);
|
||||
rdr.key_fn_tmpl_decl(fn_tmpl_decl, id);
|
||||
rdr.map_xml_node_to_decl(node, fn_tmpl_decl);
|
||||
|
||||
unsigned parm_index = 0;
|
||||
for (xmlNodePtr n = xmlFirstElementChild(node);
|
||||
@@ -5428,7 +5635,8 @@ build_function_tdecl(reader& rdr,
|
||||
}
|
||||
else if (function_decl_sptr f =
|
||||
build_function_decl_if_not_suppressed(rdr, n, class_decl_sptr(),
|
||||
/*add_to_current_scope=*/true))
|
||||
/*add_to_current_scope=*/true,
|
||||
/*add_to_exported_decls=*/true))
|
||||
fn_tmpl_decl->set_pattern(f);
|
||||
}
|
||||
|
||||
@@ -5449,12 +5657,12 @@ build_function_tdecl(reader& rdr,
|
||||
///
|
||||
/// @return the newly built function_tdecl upon successful
|
||||
/// completion, a null pointer otherwise.
|
||||
static shared_ptr<class_tdecl>
|
||||
build_class_tdecl(reader& rdr,
|
||||
static class_tdecl_sptr
|
||||
build_class_tdecl(reader& rdr,
|
||||
const xmlNodePtr node,
|
||||
bool add_to_current_scope)
|
||||
{
|
||||
shared_ptr<class_tdecl> nil, result;
|
||||
class_tdecl_sptr nil, result;
|
||||
|
||||
if (!xmlStrEqual(node->name, BAD_CAST("class-template-decl")))
|
||||
return nil;
|
||||
@@ -5476,7 +5684,10 @@ build_class_tdecl(reader& rdr,
|
||||
class_tdecl_sptr class_tmpl (new class_tdecl(env, loc, vis));
|
||||
maybe_set_artificial_location(rdr, node, class_tmpl);
|
||||
|
||||
rdr.push_decl_to_current_scope(class_tmpl, add_to_current_scope);
|
||||
if (add_to_current_scope)
|
||||
rdr.push_decl_to_scope(class_tmpl, node);
|
||||
rdr.key_class_tmpl_decl(class_tmpl, id);
|
||||
rdr.map_xml_node_to_decl(node, class_tmpl);
|
||||
|
||||
unsigned parm_index = 0;
|
||||
for (xmlNodePtr n = xmlFirstElementChild(node);
|
||||
@@ -5555,10 +5766,9 @@ build_type_tparameter(reader& rdr,
|
||||
maybe_set_artificial_location(rdr, node, result);
|
||||
|
||||
if (id.empty())
|
||||
rdr.push_decl_to_current_scope(dynamic_pointer_cast<decl_base>(result),
|
||||
/*add_to_current_scope=*/true);
|
||||
rdr.push_decl_to_scope(is_decl(result), node);
|
||||
else
|
||||
rdr.push_and_key_type_decl(result, id, /*add_to_current_scope=*/true);
|
||||
rdr.push_and_key_type_decl(result, node, /*add_to_current_scope=*/true);
|
||||
|
||||
rdr.maybe_canonicalize_type(result, /*force_delay=*/false);
|
||||
|
||||
@@ -5592,8 +5802,7 @@ build_type_composition(reader& rdr,
|
||||
|
||||
type_base_sptr composed_type;
|
||||
result.reset(new type_composition(index, tdecl, composed_type));
|
||||
rdr.push_decl_to_current_scope(dynamic_pointer_cast<decl_base>(result),
|
||||
/*add_to_current_scope=*/true);
|
||||
rdr.push_decl_to_scope(is_decl(result), node);
|
||||
|
||||
for (xmlNodePtr n = xmlFirstElementChild(node);
|
||||
n;
|
||||
@@ -5665,8 +5874,7 @@ build_non_type_tparameter(reader& rdr,
|
||||
|
||||
r.reset(new non_type_tparameter(index, tdecl, name, type, loc));
|
||||
maybe_set_artificial_location(rdr, node, r);
|
||||
rdr.push_decl_to_current_scope(dynamic_pointer_cast<decl_base>(r),
|
||||
/*add_to_current_scope=*/true);
|
||||
rdr.push_decl_to_scope(is_decl(r), node);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -5721,7 +5929,7 @@ build_template_tparameter(reader& rdr,
|
||||
template_tparameter_sptr result(new template_tparameter(index, tdecl,
|
||||
name, loc));
|
||||
maybe_set_artificial_location(rdr, node, result);
|
||||
rdr.push_decl_to_current_scope(result, /*add_to_current_scope=*/true);
|
||||
rdr.push_decl_to_scope(result, node);
|
||||
|
||||
// Go parse template parameters that are children nodes
|
||||
int parm_index = 0;
|
||||
@@ -5795,6 +6003,7 @@ build_type(reader& rdr,
|
||||
|| (t = build_reference_type_def(rdr, node , add_to_current_scope))
|
||||
|| (t = build_function_type(rdr, node, add_to_current_scope))
|
||||
|| (t = build_array_type_def(rdr, node, add_to_current_scope))
|
||||
|| (t = build_subrange_type(rdr, node, add_to_current_scope))
|
||||
|| (t = build_enum_type_decl_if_not_suppressed(rdr, node,
|
||||
add_to_current_scope))
|
||||
|| (t = build_typedef_decl(rdr, node, add_to_current_scope))
|
||||
@@ -6005,7 +6214,8 @@ handle_function_decl(reader& rdr,
|
||||
bool add_to_current_scope)
|
||||
{
|
||||
return build_function_decl_if_not_suppressed(rdr, node, class_decl_sptr(),
|
||||
add_to_current_scope);
|
||||
add_to_current_scope,
|
||||
/*add_to_exported_decls=*/true);
|
||||
}
|
||||
|
||||
/// Parse a 'class-decl' xml element.
|
||||
@@ -6214,7 +6424,7 @@ read_corpus_from_abixml_file(const string& path,
|
||||
bool
|
||||
load_canonical_type_ids(fe_iface& iface, const string &file_path)
|
||||
{
|
||||
xml_reader::reader& rdr = dynamic_cast<xml_reader::reader&>(iface)
|
||||
abixml::reader& rdr = dynamic_cast<abixml::reader&>(iface);
|
||||
|
||||
xmlDocPtr doc = xmlReadFile(file_path.c_str(), NULL, XML_PARSE_NOERROR);
|
||||
if (!doc)
|
||||
@@ -6273,7 +6483,7 @@ load_canonical_type_ids(fe_iface& iface, const string &file_path)
|
||||
// that are not canonicalized. Look into function
|
||||
// hash_as_canonical_type_or_constant for the details.
|
||||
&& v != 0xdeadbabe)
|
||||
rdr.get_environment()->get_type_id_canonical_type_map()[id] = v;
|
||||
rdr.get_environment().get_type_id_canonical_type_map()[id] = v;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2016-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2016-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
///
|
||||
|
||||
+127
-8
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2017-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2017-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -402,8 +402,12 @@ represent(const var_diff_sptr &diff,
|
||||
const bool o_anon = !!is_anonymous_data_member(o);
|
||||
const bool n_anon = !!is_anonymous_data_member(n);
|
||||
const bool is_strict_anonymous_data_member_change = o_anon && n_anon;
|
||||
const string o_name = o->get_qualified_name();
|
||||
const string n_name = n->get_qualified_name();
|
||||
const string o_name = (is_data_member_of_anonymous_class_or_union(o)
|
||||
? o->get_name()
|
||||
: o->get_qualified_name());
|
||||
const string n_name = (is_data_member_of_anonymous_class_or_union(n)
|
||||
? n->get_name()
|
||||
: n->get_qualified_name());
|
||||
const uint64_t o_size = get_var_size_in_bits(o);
|
||||
const uint64_t n_size = get_var_size_in_bits(n);
|
||||
const uint64_t o_offset = get_data_member_offset(o);
|
||||
@@ -712,6 +716,77 @@ represent(const var_diff_sptr &diff,
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
/// Represent the changes carried by an instance of @ref subrange_diff
|
||||
/// that represent a difference between two ranges.
|
||||
///
|
||||
/// @param diff diff the diff node to represent.
|
||||
///
|
||||
/// @param ctxt the diff context to use.
|
||||
///
|
||||
/// @param local_only if true, only display local changes.
|
||||
///
|
||||
/// @param out the output stream to send the representation to.
|
||||
///
|
||||
/// @param indent the indentation string to use for the change report.
|
||||
void
|
||||
represent(const subrange_diff& d,
|
||||
const diff_context_sptr ctxt,
|
||||
ostream& out,
|
||||
const string& indent,
|
||||
bool local_only)
|
||||
{
|
||||
array_type_def::subrange_sptr o = d.first_subrange();
|
||||
array_type_def::subrange_sptr n = d.second_subrange();
|
||||
string oor = o->get_pretty_representation();
|
||||
string nr = n->get_pretty_representation();
|
||||
string on = o->get_name();
|
||||
string nn = n->get_name();
|
||||
int64_t olb = o->get_lower_bound();
|
||||
int64_t nlb = n->get_lower_bound();
|
||||
int64_t oub = o->get_upper_bound();
|
||||
int64_t nub = n->get_upper_bound();
|
||||
|
||||
if (on != nn)
|
||||
{
|
||||
out << indent << "name of range changed from '"
|
||||
<< on << "' to '" << nn << "'\n";
|
||||
}
|
||||
|
||||
if (olb != nlb)
|
||||
{
|
||||
out << indent << "lower bound of range '"
|
||||
<< on
|
||||
<< "' change from '";
|
||||
emit_num_value(olb, *ctxt, out);
|
||||
out << "' to '";
|
||||
emit_num_value(nlb, *ctxt, out);
|
||||
out << "'\n";
|
||||
}
|
||||
|
||||
if (oub != nub)
|
||||
{
|
||||
out << indent << "upper bound of range '"
|
||||
<< on
|
||||
<< "' change from '";
|
||||
emit_num_value(oub, *ctxt, out);
|
||||
out << "' to '";
|
||||
emit_num_value(nub, *ctxt, out);
|
||||
out << "'\n";
|
||||
}
|
||||
|
||||
if (!local_only)
|
||||
{
|
||||
diff_sptr dif = d.underlying_type_diff();
|
||||
if (dif && dif->to_be_reported())
|
||||
{
|
||||
// report range underlying type changes
|
||||
out << indent << "underlying type of range '"
|
||||
<< oor << "' changed:\n";
|
||||
dif->report(out, indent + " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Report the size and alignment changes of a type.
|
||||
///
|
||||
/// @param first the first type to consider.
|
||||
@@ -763,12 +838,12 @@ report_size_and_alignment_changes(type_or_decl_base_sptr first,
|
||||
// arrays ...
|
||||
out << indent << "array type size changed from ";
|
||||
if (first_array->is_infinite())
|
||||
out << "infinity";
|
||||
out << "\'unknown\'";
|
||||
else
|
||||
emit_num_value(first_array->get_size_in_bits(), *ctxt, out);
|
||||
out << " to ";
|
||||
if (second_array->is_infinite())
|
||||
out << "infinity";
|
||||
out << "\'unknown\'";
|
||||
else
|
||||
emit_num_value(second_array->get_size_in_bits(), *ctxt, out);
|
||||
out << "\n";
|
||||
@@ -797,14 +872,14 @@ report_size_and_alignment_changes(type_or_decl_base_sptr first,
|
||||
<< " changed length from ";
|
||||
|
||||
if ((*i)->is_infinite())
|
||||
out << "infinity";
|
||||
out << "\'unknown\'";
|
||||
else
|
||||
out << (*i)->get_length();
|
||||
|
||||
out << " to ";
|
||||
|
||||
if ((*j)->is_infinite())
|
||||
out << "infinity";
|
||||
out << "\'unknown\'";
|
||||
else
|
||||
out << (*j)->get_length();
|
||||
out << "\n";
|
||||
@@ -894,7 +969,8 @@ report_name_size_and_alignment_changes(decl_base_sptr first,
|
||||
string fn = first->get_qualified_name(),
|
||||
sn = second->get_qualified_name();
|
||||
|
||||
if (fn != sn)
|
||||
if (!(first->get_is_anonymous() && second->get_is_anonymous())
|
||||
&& fn != sn)
|
||||
{
|
||||
if (!(ctxt->get_allowed_category() & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
|
||||
&& filtering::has_harmless_name_change(first, second))
|
||||
@@ -1070,6 +1146,49 @@ maybe_report_diff_for_member(const decl_base_sptr& decl1,
|
||||
return reported;
|
||||
}
|
||||
|
||||
/// Report the differences between two generic variables.
|
||||
///
|
||||
/// @param decl1 the first version of the variable.
|
||||
///
|
||||
/// @param decl2 the second version of the variable.
|
||||
///
|
||||
/// @param ctxt the context of the diff.
|
||||
///
|
||||
/// @param out the output stream to emit the change report to.
|
||||
///
|
||||
/// @param indent the indentation prefix to emit.
|
||||
///
|
||||
/// @return true if any text has been emitted to the output stream.
|
||||
bool
|
||||
maybe_report_diff_for_variable(const decl_base_sptr& decl1,
|
||||
const decl_base_sptr& decl2,
|
||||
const diff_context_sptr& ctxt,
|
||||
ostream& out,
|
||||
const string& indent)
|
||||
{
|
||||
bool reported = false;
|
||||
|
||||
var_decl_sptr var1 = is_var_decl(decl1);
|
||||
var_decl_sptr var2 = is_var_decl(decl2);
|
||||
|
||||
if (!var1 || !var2)
|
||||
return reported;
|
||||
|
||||
if (filtering::is_var_1_dim_unknown_size_array_change(var1, var2))
|
||||
{
|
||||
uint64_t var_size_in_bits = var1->get_symbol()->get_size() * 8;
|
||||
|
||||
out << indent;
|
||||
show_offset_or_size("size of variable symbol (",
|
||||
var_size_in_bits, *ctxt, out);
|
||||
out << ") hasn't changed\n"
|
||||
<< indent << "but it does have a harmless type change\n";
|
||||
reported = true;
|
||||
}
|
||||
|
||||
return reported;
|
||||
}
|
||||
|
||||
/// Report the difference between two ELF symbols, if there is any.
|
||||
///
|
||||
/// @param symbol1 the first symbol to consider.
|
||||
|
||||
+15
-1
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -156,6 +156,13 @@ represent(const var_diff_sptr &diff,
|
||||
const string& indent = "",
|
||||
bool local_only = false);
|
||||
|
||||
void
|
||||
represent(const subrange_diff& diff,
|
||||
const diff_context_sptr ctxt,
|
||||
ostream& out,
|
||||
const string& indent = "",
|
||||
bool local_only = false);
|
||||
|
||||
void
|
||||
report_size_and_alignment_changes(type_or_decl_base_sptr first,
|
||||
type_or_decl_base_sptr second,
|
||||
@@ -206,6 +213,13 @@ maybe_report_diff_for_member(const decl_base_sptr& decl1,
|
||||
ostream& out,
|
||||
const string& indent);
|
||||
|
||||
bool
|
||||
maybe_report_diff_for_variable(const decl_base_sptr& decl1,
|
||||
const decl_base_sptr& decl2,
|
||||
const diff_context_sptr& ctxt,
|
||||
ostream& out,
|
||||
const string& indent);
|
||||
|
||||
void
|
||||
maybe_report_diff_for_symbol(const elf_symbol_sptr& symbol1,
|
||||
const elf_symbol_sptr& symbol2,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2016-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2016-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -570,11 +570,22 @@ class type_suppression::priv
|
||||
type_suppression::type_kind type_kind_;
|
||||
bool consider_reach_kind_;
|
||||
type_suppression::reach_kind reach_kind_;
|
||||
bool has_size_change_;
|
||||
// The data members a class needs to have to match this suppression
|
||||
// specification. These might be selected by a regular expression.
|
||||
string_set_type potential_data_members_;
|
||||
// The regular expression string that selects the potential data
|
||||
// members of the class.
|
||||
string potential_data_members_regex_str_;
|
||||
// The compiled regular expression that selects the potential data
|
||||
// members of the class.
|
||||
mutable regex::regex_t_sptr potential_data_members_regex_;
|
||||
type_suppression::insertion_ranges insertion_ranges_;
|
||||
unordered_set<string> source_locations_to_keep_;
|
||||
unordered_set<string> source_locations_to_keep_;
|
||||
string source_location_to_keep_regex_str_;
|
||||
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_;
|
||||
|
||||
priv();
|
||||
|
||||
@@ -590,7 +601,8 @@ public:
|
||||
consider_type_kind_(consider_type_kind),
|
||||
type_kind_(type_kind),
|
||||
consider_reach_kind_(consider_reach_kind),
|
||||
reach_kind_(reach_kind)
|
||||
reach_kind_(reach_kind),
|
||||
has_size_change_(false)
|
||||
{}
|
||||
|
||||
/// Get the regular expression object associated to the 'type_name_regex'
|
||||
@@ -677,6 +689,34 @@ public:
|
||||
set_source_location_to_keep_regex(regex::regex_t_sptr r)
|
||||
{source_location_to_keep_regex_ = r;}
|
||||
|
||||
/// Getter for the "potential_data_member_names_regex" object.
|
||||
///
|
||||
/// This regex object matches the names of the data members that are
|
||||
/// needed for this suppression specification to select the type.
|
||||
///
|
||||
/// @return the "potential_data_member_names_regex" object.
|
||||
const regex::regex_t_sptr
|
||||
get_potential_data_member_names_regex() const
|
||||
{
|
||||
if (!potential_data_members_regex_
|
||||
&& !potential_data_members_regex_str_.empty())
|
||||
{
|
||||
potential_data_members_regex_ =
|
||||
regex::compile(potential_data_members_regex_str_);
|
||||
}
|
||||
return potential_data_members_regex_;
|
||||
}
|
||||
|
||||
/// Setter for the "potential_data_member_names_regex" object.
|
||||
///
|
||||
/// This regex object matches the names of the data members that are
|
||||
/// needed for this suppression specification to select the type.
|
||||
///
|
||||
/// @param r the new "potential_data_member_names_regex" object.
|
||||
void
|
||||
set_potential_data_member_names_regex(regex::regex_t_sptr &r)
|
||||
{potential_data_members_regex_ = r;}
|
||||
|
||||
friend class type_suppression;
|
||||
}; // class type_suppression::priv
|
||||
|
||||
|
||||
+586
-100
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2016-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2016-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -24,6 +24,7 @@ ABG_BEGIN_EXPORT_DECLARATIONS
|
||||
#include "abg-suppression.h"
|
||||
#include "abg-tools-utils.h"
|
||||
#include "abg-fe-iface.h"
|
||||
#include "abg-comparison.h"
|
||||
|
||||
ABG_END_EXPORT_DECLARATIONS
|
||||
// </headers defining libabigail's API>
|
||||
@@ -36,9 +37,28 @@ namespace abigail
|
||||
namespace suppr
|
||||
{
|
||||
|
||||
// Inject the abigail::comparison namespace in here.
|
||||
using namespace comparison;
|
||||
|
||||
using std::dynamic_pointer_cast;
|
||||
using regex::regex_t_sptr;
|
||||
|
||||
/// @return the string constant "offset_of_flexible_array_data_member".
|
||||
static const string&
|
||||
OFFSET_OF_FLEXIBLE_ARRAY_DATA_MEMBER_STRING()
|
||||
{
|
||||
static string s = "offset_of_flexible_array_data_member";
|
||||
return s;
|
||||
}
|
||||
|
||||
/// @return the string constant "end";
|
||||
static const string&
|
||||
END_STRING()
|
||||
{
|
||||
static string s = "end";
|
||||
return s;
|
||||
}
|
||||
|
||||
// <parsing stuff>
|
||||
|
||||
// section parsing
|
||||
@@ -270,6 +290,67 @@ suppression_base::has_soname_related_property() const
|
||||
&& get_soname_not_regex_str().empty()));
|
||||
}
|
||||
|
||||
/// Constructor of the @ref negated_suppression_base.
|
||||
negated_suppression_base::negated_suppression_base()
|
||||
{
|
||||
}
|
||||
|
||||
/// Destructor of the @ref negated_suppression_base.
|
||||
negated_suppression_base::~negated_suppression_base()
|
||||
{
|
||||
}
|
||||
|
||||
/// Test if a suppression specification is a negated suppression.
|
||||
///
|
||||
/// @param s the suppression to consider.
|
||||
///
|
||||
/// @return true iff @p s is an instance of @ref
|
||||
/// negated_suppression_base.
|
||||
bool
|
||||
is_negated_suppression(const suppression_base& s)
|
||||
{
|
||||
bool result = true;
|
||||
try
|
||||
{
|
||||
dynamic_cast<const negated_suppression_base&>(s);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Test if a suppression specification is a negated suppression.
|
||||
///
|
||||
/// @param s the suppression to consider.
|
||||
///
|
||||
/// @return true a pointer to the @ref negated_suppression_base which
|
||||
/// @p s, or nil if it's not a negated suppression.
|
||||
/// negated_suppression_base.
|
||||
const negated_suppression_base*
|
||||
is_negated_suppression(const suppression_base* s)
|
||||
{
|
||||
const negated_suppression_base* result = nullptr;
|
||||
result = dynamic_cast<const negated_suppression_base*>(s);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Test if a suppression specification is a negated suppression.
|
||||
///
|
||||
/// @param s the suppression to consider.
|
||||
///
|
||||
/// @return true a pointer to the @ref negated_suppression_base which
|
||||
/// @p s, or nil if it's not a negated suppression.
|
||||
/// negated_suppression_base.
|
||||
negated_suppression_sptr
|
||||
is_negated_suppression(const suppression_sptr& s)
|
||||
{
|
||||
negated_suppression_sptr result;
|
||||
result = dynamic_pointer_cast<negated_suppression_base>(s);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Check if the SONAMEs of the two binaries being compared match the
|
||||
/// content of the properties "soname_regexp" and "soname_not_regexp"
|
||||
/// of the current suppression specification.
|
||||
@@ -569,6 +650,52 @@ void
|
||||
type_suppression::set_reach_kind(reach_kind k)
|
||||
{priv_->reach_kind_ = k;}
|
||||
|
||||
/// Getter of the "has_size_change" property.
|
||||
///
|
||||
/// @return the value of the "has_size_change" property.
|
||||
bool
|
||||
type_suppression::get_has_size_change() const
|
||||
{return priv_->has_size_change_;}
|
||||
|
||||
/// Setter of the "has_size_change" property.
|
||||
///
|
||||
/// @param flag the new value of the "has_size_change" property.
|
||||
void
|
||||
type_suppression::set_has_size_change(bool flag)
|
||||
{priv_->has_size_change_ = flag;}
|
||||
|
||||
/// Getter of the "potential_data_member_names" property.
|
||||
///
|
||||
/// @return the set of potential data member names of this
|
||||
/// suppression.
|
||||
const unordered_set<string>&
|
||||
type_suppression::get_potential_data_member_names() const
|
||||
{return priv_->potential_data_members_;}
|
||||
|
||||
/// Setter of the "potential_data_member_names" property.
|
||||
///
|
||||
/// @param s the new set of potential data member names of this
|
||||
/// suppression.
|
||||
void
|
||||
type_suppression::set_potential_data_member_names
|
||||
(const string_set_type& s) const
|
||||
{priv_->potential_data_members_ = s;}
|
||||
|
||||
/// Getter of the "potential_data_member_names_regex" string.
|
||||
///
|
||||
/// @return the "potential_data_member_names_regex" string.
|
||||
const string&
|
||||
type_suppression::get_potential_data_member_names_regex_str() const
|
||||
{return priv_->potential_data_members_regex_str_;}
|
||||
|
||||
/// Setter of the "potential_data_member_names_regex" string.
|
||||
///
|
||||
/// @param d the new "potential_data_member_names_regex" string.
|
||||
void
|
||||
type_suppression::set_potential_data_member_names_regex_str
|
||||
(const string& d) const
|
||||
{priv_->potential_data_members_regex_str_ = d;}
|
||||
|
||||
/// Setter for the vector of data member insertion ranges that
|
||||
/// specifies where a data member is inserted as far as this
|
||||
/// suppression specification is concerned.
|
||||
@@ -659,6 +786,28 @@ void
|
||||
type_suppression::set_changed_enumerator_names(const vector<string>& n)
|
||||
{priv_->changed_enumerator_names_ = n;}
|
||||
|
||||
/// Getter of the vector of the regular expression strings for changed
|
||||
/// enumerators that are supposed to be suppressed. Note that this
|
||||
/// will be "valid" only if the type suppression has the
|
||||
/// 'type_kind = enum' property.
|
||||
///
|
||||
/// @return the vector of the regular expression strings that are
|
||||
/// supposed to match enumertor names to be suppressed.
|
||||
const vector<regex::regex_t_sptr>&
|
||||
type_suppression::get_changed_enumerators_regexp() const
|
||||
{return priv_->changed_enumerators_regexp_;}
|
||||
|
||||
/// Setter of the vector of the regular expression strings for changed
|
||||
/// enumerators that are supposed to be suppressed. Note that this
|
||||
/// will be "valid" only if the type suppression has the
|
||||
/// 'type_kind = enum' property.
|
||||
///
|
||||
/// @param n the vector of the regular expression strings that are
|
||||
/// supposed to match enumertor names to be suppressed.
|
||||
void
|
||||
type_suppression::set_changed_enumerators_regexp(const vector<regex::regex_t_sptr>& n)
|
||||
{priv_->changed_enumerators_regexp_ = n;}
|
||||
|
||||
/// Evaluate this suppression specification on a given diff node and
|
||||
/// say if the diff node should be suppressed or not.
|
||||
///
|
||||
@@ -778,6 +927,43 @@ type_suppression::suppresses_diff(const diff* diff) const
|
||||
// Now let's consider class diffs in the context of a suppr spec
|
||||
// that contains properties like "has_data_member_inserted_*".
|
||||
|
||||
const class_or_union_diff* cou_diff = is_class_or_union_diff(d);
|
||||
if (cou_diff)
|
||||
{
|
||||
class_or_union_sptr f = cou_diff->first_class_or_union();
|
||||
// We are looking at the a class or union diff ...
|
||||
if (!get_potential_data_member_names().empty())
|
||||
{
|
||||
// ... and the suppr spec has a:
|
||||
//
|
||||
// "has_data_member = {foo, bar}" property
|
||||
//
|
||||
for (string var_name : get_potential_data_member_names())
|
||||
if (!f->find_data_member(var_name))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!get_potential_data_member_names_regex_str().empty())
|
||||
{
|
||||
if (const regex_t_sptr& data_member_name_regex =
|
||||
priv_->get_potential_data_member_names_regex())
|
||||
{
|
||||
bool data_member_matched = false;
|
||||
for (var_decl_sptr dm : f->get_data_members())
|
||||
{
|
||||
if (regex::match(data_member_name_regex, dm->get_name()))
|
||||
{
|
||||
data_member_matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!data_member_matched)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate has_data_member_inserted_*" clauses.
|
||||
const class_diff* klass_diff = dynamic_cast<const class_diff*>(d);
|
||||
if (klass_diff)
|
||||
{
|
||||
@@ -786,75 +972,54 @@ type_suppression::suppresses_diff(const diff* diff) const
|
||||
{
|
||||
// ... and the suppr spec contains a
|
||||
// "has_data_member_inserted_*" clause ...
|
||||
if (klass_diff->deleted_data_members().empty()
|
||||
&& (klass_diff->first_class_decl()->get_size_in_bits()
|
||||
<= klass_diff->second_class_decl()->get_size_in_bits()))
|
||||
if ((klass_diff->first_class_decl()->get_size_in_bits()
|
||||
== klass_diff->second_class_decl()->get_size_in_bits())
|
||||
|| get_has_size_change())
|
||||
{
|
||||
// That "has_data_member_inserted_*" clause doesn't hold
|
||||
// if the class has deleted data members or shrunk.
|
||||
// if the class changed size, unless the user specified
|
||||
// that suppression applies to types that have size
|
||||
// change.
|
||||
|
||||
const class_decl_sptr& first_type_decl =
|
||||
klass_diff->first_class_decl();
|
||||
|
||||
for (string_decl_base_sptr_map::const_iterator m =
|
||||
klass_diff->inserted_data_members().begin();
|
||||
m != klass_diff->inserted_data_members().end();
|
||||
++m)
|
||||
if (klass_diff->inserted_data_members().empty()
|
||||
&& klass_diff->changed_data_members().empty())
|
||||
// So there is a has_data_member_inserted_* clause,
|
||||
// but no data member was inserted. That means the
|
||||
// clause is falsified.
|
||||
return false;
|
||||
|
||||
// All inserted data members must be in an allowed
|
||||
// insertion range.
|
||||
for (const auto& m : klass_diff->inserted_data_members())
|
||||
{
|
||||
decl_base_sptr member = m->second;
|
||||
size_t dm_offset = get_data_member_offset(member);
|
||||
decl_base_sptr member = m.second;
|
||||
bool matched = false;
|
||||
|
||||
for (insertion_ranges::const_iterator i =
|
||||
get_data_member_insertion_ranges().begin();
|
||||
i != get_data_member_insertion_ranges().end();
|
||||
++i)
|
||||
{
|
||||
type_suppression::insertion_range_sptr range = *i;
|
||||
uint64_t range_begin_val = 0, range_end_val = 0;
|
||||
if (!type_suppression::insertion_range::eval_boundary
|
||||
(range->begin(), first_type_decl, range_begin_val))
|
||||
break;
|
||||
if (!type_suppression::insertion_range::eval_boundary
|
||||
(range->end(), first_type_decl, range_end_val))
|
||||
break;
|
||||
|
||||
uint64_t range_begin = range_begin_val;
|
||||
uint64_t range_end = range_end_val;
|
||||
|
||||
if (insertion_range::boundary_value_is_end(range_begin)
|
||||
&& insertion_range::boundary_value_is_end(range_end))
|
||||
{
|
||||
// This idiom represents the predicate
|
||||
// "has_data_member_inserted_at = end"
|
||||
if (dm_offset >
|
||||
get_data_member_offset(get_last_data_member
|
||||
(first_type_decl)))
|
||||
{
|
||||
// So the data member was added after
|
||||
// last data member of the klass. That
|
||||
// matches the suppr spec
|
||||
// "has_data_member_inserted_at = end".
|
||||
matched = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (range_begin > range_end)
|
||||
// Wrong suppr spec. Ignore it.
|
||||
continue;
|
||||
|
||||
if (dm_offset < range_begin || dm_offset > range_end)
|
||||
// The offset of the added data member doesn't
|
||||
// match the insertion range specified. So
|
||||
// the diff object won't be suppressed.
|
||||
continue;
|
||||
|
||||
// If we reached this point, then all the
|
||||
// insertion range constraints have been
|
||||
// satisfied. So
|
||||
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()))
|
||||
matched = true;
|
||||
}
|
||||
|
||||
if (!matched)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Similarly, each data member that replaced another one
|
||||
// must be in an allowed insertion range.
|
||||
for (const auto& m : klass_diff->changed_data_members())
|
||||
{
|
||||
var_decl_sptr member = m.second->second_var();
|
||||
bool matched = false;
|
||||
|
||||
for (const auto& range : get_data_member_insertion_ranges())
|
||||
if (is_data_member_offset_in_range(member, range,
|
||||
first_type_decl.get()))
|
||||
matched = true;
|
||||
|
||||
if (!matched)
|
||||
return false;
|
||||
}
|
||||
@@ -875,9 +1040,12 @@ type_suppression::suppresses_diff(const diff* diff) const
|
||||
// ... and yet carries some changed enumerators!
|
||||
&& !enum_dif->changed_enumerators().empty())
|
||||
{
|
||||
// Make sure that all changed enumerators are listed in the
|
||||
// vector of enumerator names returned by the
|
||||
// get_changed_enumerator_names() member function.
|
||||
|
||||
// Make sure that all changed enumerators are either:
|
||||
// 1. listed in the vector of enumerator names returned
|
||||
// by the get_changed_enumerator_names() member function
|
||||
// 2. match a regular expression returned by the
|
||||
// get_changed_enumerators_regexp() member function
|
||||
bool matched = true;
|
||||
for (string_changed_enumerator_map::const_iterator i =
|
||||
enum_dif->changed_enumerators().begin();
|
||||
@@ -885,13 +1053,20 @@ type_suppression::suppresses_diff(const diff* diff) const
|
||||
++i)
|
||||
{
|
||||
matched &= true;
|
||||
if (std::find(get_changed_enumerator_names().begin(),
|
||||
get_changed_enumerator_names().end(),
|
||||
i->first) == get_changed_enumerator_names().end())
|
||||
{
|
||||
matched &= false;
|
||||
break;
|
||||
}
|
||||
if ((std::find(get_changed_enumerator_names().begin(),
|
||||
get_changed_enumerator_names().end(),
|
||||
i->first) == get_changed_enumerator_names().end())
|
||||
&&
|
||||
(std::find_if(get_changed_enumerators_regexp().begin(),
|
||||
get_changed_enumerators_regexp().end(),
|
||||
[&] (const regex_t_sptr& enum_regexp)
|
||||
{
|
||||
return regex::match(enum_regexp, i->first);
|
||||
}) == get_changed_enumerators_regexp().end()))
|
||||
{
|
||||
matched &= false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched)
|
||||
return false;
|
||||
@@ -1323,6 +1498,25 @@ type_suppression::insertion_range::create_fn_call_expr_boundary(const string& s)
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Create a named boundary.
|
||||
///
|
||||
/// The return value is to be used as a boundary for an instance of
|
||||
/// @ref type_suppression::insertion_range. The value of that
|
||||
/// boundary is a named constant that is to be evaluated to an integer
|
||||
/// value, in the context of a @ref class_decl. That evaluate is
|
||||
/// performed by the function
|
||||
/// type_suppression::insertion_range::eval_boundary().
|
||||
///
|
||||
/// @param name the name of the boundary.
|
||||
///
|
||||
/// @return the newly created named boundary.
|
||||
type_suppression::insertion_range::named_boundary_sptr
|
||||
type_suppression::insertion_range::create_named_boundary(const string& name)
|
||||
{
|
||||
named_boundary_sptr result(new named_boundary(name));
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Evaluate an insertion range boundary to get a resulting integer
|
||||
/// value.
|
||||
///
|
||||
@@ -1335,9 +1529,9 @@ type_suppression::insertion_range::create_fn_call_expr_boundary(const string& s)
|
||||
/// @return true iff the evaluation was successful and @p value
|
||||
/// contains the resulting value.
|
||||
bool
|
||||
type_suppression::insertion_range::eval_boundary(boundary_sptr boundary,
|
||||
class_decl_sptr context,
|
||||
uint64_t& value)
|
||||
type_suppression::insertion_range::eval_boundary(const boundary_sptr boundary,
|
||||
const class_or_union* context,
|
||||
uint64_t& value)
|
||||
{
|
||||
if (integer_boundary_sptr b = is_integer_boundary(boundary))
|
||||
{
|
||||
@@ -1347,38 +1541,84 @@ type_suppression::insertion_range::eval_boundary(boundary_sptr boundary,
|
||||
else if (fn_call_expr_boundary_sptr b = is_fn_call_expr_boundary(boundary))
|
||||
{
|
||||
ini::function_call_expr_sptr fn_call = b->as_function_call_expr();
|
||||
if ((fn_call->get_name() == "offset_of"
|
||||
|| fn_call->get_name() == "offset_after")
|
||||
if (fn_call
|
||||
&& (fn_call->get_name() == "offset_of"
|
||||
|| fn_call->get_name() == "offset_after"
|
||||
|| fn_call->get_name() == "offset_of_first_data_member_regexp"
|
||||
|| fn_call->get_name() == "offset_of_last_data_member_regexp")
|
||||
&& fn_call->get_arguments().size() == 1)
|
||||
{
|
||||
string member_name = fn_call->get_arguments()[0];
|
||||
for (class_decl::data_members::const_iterator it =
|
||||
context->get_data_members().begin();
|
||||
it != context->get_data_members().end();
|
||||
++it)
|
||||
if (fn_call->get_name() == "offset_of"
|
||||
|| fn_call->get_name() == "offset_after")
|
||||
{
|
||||
if (!get_data_member_is_laid_out(**it))
|
||||
continue;
|
||||
if ((*it)->get_name() == member_name)
|
||||
string member_name = fn_call->get_arguments()[0];
|
||||
for (class_decl::data_members::const_iterator it =
|
||||
context->get_data_members().begin();
|
||||
it != context->get_data_members().end();
|
||||
++it)
|
||||
{
|
||||
if (fn_call->get_name() == "offset_of")
|
||||
value = get_data_member_offset(*it);
|
||||
else if (fn_call->get_name() == "offset_after")
|
||||
if (!get_data_member_is_laid_out(**it))
|
||||
continue;
|
||||
if ((*it)->get_name() == member_name)
|
||||
{
|
||||
if (!get_next_data_member_offset(context, *it, value))
|
||||
if (fn_call->get_name() == "offset_of")
|
||||
value = get_data_member_offset(*it);
|
||||
else if (fn_call->get_name() == "offset_after")
|
||||
{
|
||||
value = get_data_member_offset(*it) +
|
||||
(*it)->get_type()->get_size_in_bits();
|
||||
if (!get_next_data_member_offset(context, *it, value))
|
||||
{
|
||||
value = get_data_member_offset(*it) +
|
||||
(*it)->get_type()->get_size_in_bits();
|
||||
}
|
||||
}
|
||||
else
|
||||
// We should not reach this point.
|
||||
abort();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
// We should not reach this point.
|
||||
abort();
|
||||
}
|
||||
}
|
||||
else if (fn_call->get_name() == "offset_of_first_data_member_regexp"
|
||||
|| fn_call->get_name() == "offset_of_last_data_member_regexp")
|
||||
{
|
||||
string name_regexp = fn_call->get_arguments()[0];
|
||||
auto r = regex::compile(name_regexp);
|
||||
var_decl_sptr dm;
|
||||
|
||||
if (fn_call->get_name() == "offset_of_first_data_member_regexp")
|
||||
dm = find_first_data_member_matching_regexp(*context, r);
|
||||
else if (fn_call->get_name() == "offset_of_last_data_member_regexp")
|
||||
dm = find_last_data_member_matching_regexp(*context, r);
|
||||
|
||||
if (dm)
|
||||
{
|
||||
value = get_data_member_offset(dm);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (named_boundary_sptr b = is_named_boundary(boundary))
|
||||
{
|
||||
if (b->get_name() == OFFSET_OF_FLEXIBLE_ARRAY_DATA_MEMBER_STRING())
|
||||
{
|
||||
// Look at the last data member of 'context' and make sure
|
||||
// its type is an array with non-finite size.
|
||||
if (var_decl_sptr dm = has_flexible_array_data_member(is_class_type(context)))
|
||||
{
|
||||
value = get_data_member_offset(dm);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (b->get_name() == END_STRING())
|
||||
{
|
||||
// The 'end' of a struct is represented by the value
|
||||
// std::numeric_limits<uint64_t>::max(), recognized by
|
||||
// type_suppression::insertion_range::boundary_value_is_end.
|
||||
value = std::numeric_limits<uint64_t>::max();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1408,7 +1648,8 @@ is_integer_boundary(type_suppression::insertion_range::boundary_sptr b)
|
||||
{return dynamic_pointer_cast<type_suppression::insertion_range::integer_boundary>(b);}
|
||||
|
||||
/// Tests if a given instance of @ref
|
||||
/// type_suppression::insertion_range::boundary is actually an function call expression boundary.
|
||||
/// type_suppression::insertion_range::boundary is actually a
|
||||
/// function call expression boundary.
|
||||
///
|
||||
/// @param b the boundary to test.
|
||||
///
|
||||
@@ -1420,6 +1661,18 @@ type_suppression::insertion_range::fn_call_expr_boundary_sptr
|
||||
is_fn_call_expr_boundary(type_suppression::insertion_range::boundary_sptr b)
|
||||
{return dynamic_pointer_cast<type_suppression::insertion_range::fn_call_expr_boundary>(b);}
|
||||
|
||||
/// Test if a given instance of @ref
|
||||
/// type_suppression::insertion_range::boundary is actually a named boundary.
|
||||
///
|
||||
/// @param b the boundary to consider.
|
||||
///
|
||||
/// @return the instance of @ref
|
||||
/// type_suppression::insertion_range::named_boundary if @p b is a
|
||||
/// named boundary, or nil.
|
||||
type_suppression::insertion_range::named_boundary_sptr
|
||||
is_named_boundary(type_suppression::insertion_range::boundary_sptr b)
|
||||
{return dynamic_pointer_cast<type_suppression::insertion_range::named_boundary>(b);}
|
||||
|
||||
/// The private data type of @ref
|
||||
/// type_suppression::insertion_range::boundary.
|
||||
struct type_suppression::insertion_range::boundary::priv
|
||||
@@ -1521,6 +1774,35 @@ type_suppression::insertion_range::fn_call_expr_boundary::operator ini::function
|
||||
type_suppression::insertion_range::fn_call_expr_boundary::~fn_call_expr_boundary()
|
||||
{}
|
||||
|
||||
/// The private data type for the @ref
|
||||
/// type_suppression::insertion_range::named_boundary.
|
||||
struct type_suppression::insertion_range::named_boundary::priv
|
||||
{
|
||||
string name_;
|
||||
|
||||
priv()
|
||||
{}
|
||||
|
||||
priv(const string& name)
|
||||
: name_(name)
|
||||
{}
|
||||
}; // end struct type_suppression::insertion_range::named_boundary::priv
|
||||
|
||||
/// Constructor for @ref
|
||||
/// type_suppression::insertion_range::named_boundary
|
||||
///
|
||||
/// @param name the name of the @ref named_boundary type.
|
||||
type_suppression::insertion_range::named_boundary::named_boundary(const string& name)
|
||||
: priv_(new priv(name))
|
||||
{}
|
||||
|
||||
/// Getter for the name of the named boundary.
|
||||
///
|
||||
/// @return the name of the named boundary.
|
||||
const string&
|
||||
type_suppression::insertion_range::named_boundary::get_name() const
|
||||
{return priv_->name_;}
|
||||
|
||||
/// Test if an instance of @ref suppression is an instance of @ref
|
||||
/// type_suppression.
|
||||
///
|
||||
@@ -1535,6 +1817,52 @@ is_type_suppression(suppression_sptr suppr)
|
||||
|
||||
// </type_suppression stuff>
|
||||
|
||||
// <negated_type_suppression stuff>
|
||||
|
||||
/// Constructor for @ref negated_type_suppression.
|
||||
///
|
||||
/// @param label the label of the suppression. This is just a free
|
||||
/// form comment explaining what the suppression is about.
|
||||
///
|
||||
/// @param type_name_regexp the regular expression describing the
|
||||
/// types about which diff reports should be suppressed. If it's an
|
||||
/// empty string, the parameter is ignored.
|
||||
///
|
||||
/// @param type_name the name of the type about which diff reports
|
||||
/// should be suppressed. If it's an empty string, the parameter is
|
||||
/// ignored.
|
||||
///
|
||||
/// Note that parameter @p type_name_regexp and @p type_name_regexp
|
||||
/// should not necessarily be populated. It usually is either one or
|
||||
/// the other that the user wants.
|
||||
negated_type_suppression::negated_type_suppression(const string& label,
|
||||
const string& type_name_regexp,
|
||||
const string& type_name)
|
||||
: type_suppression(label, type_name_regexp, type_name),
|
||||
negated_suppression_base()
|
||||
{
|
||||
}
|
||||
|
||||
/// Evaluate this suppression specification on a given diff node and
|
||||
/// say if the diff node should be suppressed or not.
|
||||
///
|
||||
/// @param diff the diff node to evaluate this suppression
|
||||
/// specification against.
|
||||
///
|
||||
/// @return true if @p diff should be suppressed.
|
||||
bool
|
||||
negated_type_suppression::suppresses_diff(const diff* diff) const
|
||||
{
|
||||
return !type_suppression::suppresses_diff(diff);
|
||||
}
|
||||
|
||||
/// Destructor of the @ref negated_type_suppression type.
|
||||
negated_type_suppression::~negated_type_suppression()
|
||||
{
|
||||
}
|
||||
|
||||
// </negated_type_suppression stuff>
|
||||
|
||||
/// Parse the value of the "type_kind" property in the "suppress_type"
|
||||
/// section.
|
||||
///
|
||||
@@ -1597,7 +1925,8 @@ read_type_suppression(const ini::config::section& section)
|
||||
{
|
||||
type_suppression_sptr result;
|
||||
|
||||
if (section.get_name() != "suppress_type")
|
||||
if (section.get_name() != "suppress_type"
|
||||
&& section.get_name() != "allow_type")
|
||||
return result;
|
||||
|
||||
static const char *const sufficient_props[] = {
|
||||
@@ -1626,6 +1955,13 @@ read_type_suppression(const ini::config::section& section)
|
||||
? drop_artifact->get_value()->as_string()
|
||||
: "";
|
||||
|
||||
ini::simple_property_sptr has_size_change =
|
||||
is_simple_property(section.find_property("has_size_change"));
|
||||
|
||||
string has_size_change_str = has_size_change
|
||||
? has_size_change->get_value()->as_string()
|
||||
: "";
|
||||
|
||||
ini::simple_property_sptr label =
|
||||
is_simple_property(section.find_property("label"));
|
||||
string label_str = label ? label->get_value()->as_string() : "";
|
||||
@@ -1720,6 +2056,56 @@ read_type_suppression(const ini::config::section& section)
|
||||
read_suppression_reach_kind(reach_kind_prop->get_value()->as_string());
|
||||
}
|
||||
|
||||
// Support has_data_member = {}
|
||||
string_set_type potential_data_member_names;
|
||||
if (ini::property_sptr propertee = section.find_property("has_data_member"))
|
||||
{
|
||||
// This is either has_data_member = {foo, blah} or
|
||||
// has_data_member = foo.
|
||||
ini::tuple_property_value_sptr tv;
|
||||
ini::string_property_value_sptr sv;
|
||||
if (ini::tuple_property_sptr prop = is_tuple_property(propertee))
|
||||
// Value is of the form {foo,blah}
|
||||
tv = prop->get_value();
|
||||
else if (ini::simple_property_sptr prop = is_simple_property(propertee))
|
||||
// Value is of the form foo.
|
||||
sv = prop->get_value();
|
||||
|
||||
// Ensure that the property value has the form {"foo", "blah", ...};
|
||||
// Meaning it's a tuple of one element which is a list or a string.
|
||||
if (tv
|
||||
&& tv->get_value_items().size() == 1
|
||||
&& (is_list_property_value(tv->get_value_items().front())
|
||||
|| is_string_property_value(tv->get_value_items().front())))
|
||||
{
|
||||
ini::list_property_value_sptr val =
|
||||
is_list_property_value(tv->get_value_items().front());
|
||||
if (!val)
|
||||
{
|
||||
// We have just one potential data member name,as a
|
||||
// string_property_value.
|
||||
string name =
|
||||
is_string_property_value(tv->get_value_items().front())
|
||||
->as_string();
|
||||
potential_data_member_names.insert(name);
|
||||
}
|
||||
else
|
||||
for (const string& name : val->get_content())
|
||||
potential_data_member_names.insert(name);
|
||||
}
|
||||
else if (sv)
|
||||
{
|
||||
string name = sv->as_string();
|
||||
potential_data_member_names.insert(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Support has_data_member_regexp = str
|
||||
string potential_data_member_names_regexp_str;
|
||||
if (ini::simple_property_sptr prop =
|
||||
is_simple_property(section.find_property("has_data_member_regexp")))
|
||||
potential_data_member_names_regexp_str = prop->get_value()->as_string();
|
||||
|
||||
// Support has_data_member_inserted_at
|
||||
vector<type_suppression::insertion_range_sptr> insert_ranges;
|
||||
bool consider_data_member_insertion = false;
|
||||
@@ -1730,8 +2116,10 @@ read_type_suppression(const ini::config::section& section)
|
||||
// has_data_member_inserted_at = <one-string-property-value>
|
||||
string ins_point = prop->get_value()->as_string();
|
||||
type_suppression::insertion_range::boundary_sptr begin, end;
|
||||
if (ins_point == "end")
|
||||
begin = type_suppression::insertion_range::create_integer_boundary(-1);
|
||||
if (ins_point == END_STRING())
|
||||
begin = type_suppression::insertion_range::create_named_boundary(ins_point);
|
||||
else if (ins_point == OFFSET_OF_FLEXIBLE_ARRAY_DATA_MEMBER_STRING())
|
||||
begin = type_suppression::insertion_range::create_named_boundary(ins_point);
|
||||
else if (isdigit(ins_point[0]))
|
||||
begin = type_suppression::insertion_range::create_integer_boundary
|
||||
(atoi(ins_point.c_str()));
|
||||
@@ -1758,9 +2146,9 @@ read_type_suppression(const ini::config::section& section)
|
||||
// and not (for instance):
|
||||
// has_data_member_inserted_between = {{0 , end}, {1, foo}}
|
||||
//
|
||||
// This means that the tuple_property_value contains just one
|
||||
// value, which is a list_property that itself contains 2
|
||||
// values.
|
||||
// This means that the tuple_property_value contains just one
|
||||
// value, which is a list_property that itself contains 2
|
||||
// values.
|
||||
type_suppression::insertion_range::boundary_sptr begin, end;
|
||||
ini::tuple_property_value_sptr v = prop->get_value();
|
||||
if (v
|
||||
@@ -1905,7 +2293,39 @@ read_type_suppression(const ini::config::section& section)
|
||||
changed_enumerator_names.push_back(p->get_value()->as_string());
|
||||
}
|
||||
|
||||
result.reset(new type_suppression(label_str, name_regex_str, name_str));
|
||||
/// Support 'changed_enumerators_regexp = .*_foo, bar_[0-9]+, baz'
|
||||
///
|
||||
/// If the current type is an enum and if it carries changed
|
||||
/// enumerators that match regular expressions listed in the
|
||||
/// changed_enumerators_regexp property value then it should be
|
||||
/// suppressed.
|
||||
|
||||
ini::property_sptr changed_enumerators_regexp_prop =
|
||||
section.find_property("changed_enumerators_regexp");
|
||||
|
||||
vector<regex_t_sptr> changed_enumerators_regexp;
|
||||
if (changed_enumerators_regexp_prop)
|
||||
{
|
||||
if (ini::list_property_sptr p =
|
||||
is_list_property(changed_enumerators_regexp_prop))
|
||||
{
|
||||
for (string e : p->get_value()->get_content())
|
||||
changed_enumerators_regexp.push_back(regex::compile(e));
|
||||
}
|
||||
else if (ini::simple_property_sptr p =
|
||||
is_simple_property(changed_enumerators_regexp_prop))
|
||||
{
|
||||
changed_enumerators_regexp.push_back(
|
||||
regex::compile(p->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")
|
||||
result.reset(new negated_type_suppression(label_str, name_regex_str,
|
||||
name_str));
|
||||
|
||||
if (consider_type_kind)
|
||||
{
|
||||
@@ -1919,6 +2339,13 @@ read_type_suppression(const ini::config::section& section)
|
||||
result->set_reach_kind(reach_kind);
|
||||
}
|
||||
|
||||
if (!potential_data_member_names.empty())
|
||||
result->set_potential_data_member_names(potential_data_member_names);
|
||||
|
||||
if (!potential_data_member_names_regexp_str.empty())
|
||||
result->set_potential_data_member_names_regex_str
|
||||
(potential_data_member_names_regexp_str);
|
||||
|
||||
if (consider_data_member_insertion)
|
||||
result->set_data_member_insertion_ranges(insert_ranges);
|
||||
|
||||
@@ -1950,10 +2377,17 @@ read_type_suppression(const ini::config::section& section)
|
||||
|| !srcloc_not_in.empty())))
|
||||
result->set_drops_artifact_from_ir(true);
|
||||
|
||||
if (has_size_change_str == "yes" || has_size_change_str == "true")
|
||||
result->set_has_size_change(true);
|
||||
|
||||
if (result->get_type_kind() == type_suppression::ENUM_TYPE_KIND
|
||||
&& !changed_enumerator_names.empty())
|
||||
result->set_changed_enumerator_names(changed_enumerator_names);
|
||||
|
||||
if (result->get_type_kind() == type_suppression::ENUM_TYPE_KIND
|
||||
&& !changed_enumerators_regexp.empty())
|
||||
result->set_changed_enumerators_regexp(changed_enumerators_regexp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -4836,5 +5270,57 @@ is_type_suppressed(const fe_iface& fe,
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Test if a data memer offset is in a given insertion range.
|
||||
///
|
||||
/// @param dm the data member to consider.
|
||||
///
|
||||
/// @param range the insertion range to consider.
|
||||
///
|
||||
/// @param the class (or union) type to consider as the context in
|
||||
/// which to evaluate the insertion range denoted by @p range.
|
||||
///
|
||||
/// @return true iff the offset of the data member @p dm is in the
|
||||
/// insertion range @p range in the context of the type denoted by @p
|
||||
/// context.
|
||||
bool
|
||||
is_data_member_offset_in_range(const var_decl_sptr& dm,
|
||||
const type_suppression::insertion_range_sptr& range,
|
||||
const class_or_union* context)
|
||||
{
|
||||
ABG_ASSERT(dm && range && context);
|
||||
|
||||
uint64_t range_begin = 0, range_end = 0;
|
||||
if (!type_suppression::insertion_range::eval_boundary (range->begin(),
|
||||
context,
|
||||
range_begin))
|
||||
return false;
|
||||
|
||||
if (!type_suppression::insertion_range::eval_boundary (range->end(),
|
||||
context,
|
||||
range_end))
|
||||
return false;
|
||||
|
||||
if (range_begin > range_end)
|
||||
// wrong range, ignore it.
|
||||
return false;
|
||||
|
||||
uint64_t dm_offset = get_data_member_offset(dm);
|
||||
if (type_suppression::insertion_range::boundary_value_is_end(range_begin)
|
||||
&& type_suppression::insertion_range::boundary_value_is_end(range_end))
|
||||
{
|
||||
// This idiom represents the predicate
|
||||
// "has_data_member_inserted_at = end"
|
||||
if (dm_offset > get_data_member_offset(get_last_data_member(context)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dm_offset < range_begin || dm_offset > range_end)
|
||||
// The offset of the data member is outside the range.
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}// end namespace suppr
|
||||
} // end namespace abigail
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2020-2022 Google, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
// Copyright (C) 2020-2023 Google, Inc.
|
||||
//
|
||||
// Author: Matthias Maennich
|
||||
|
||||
|
||||
+14
-13
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2020-2022 Google, Inc.
|
||||
// Copyright (C) 2020-2023 Google, Inc.
|
||||
//
|
||||
// Author: Matthias Maennich
|
||||
|
||||
@@ -99,7 +99,7 @@ private:
|
||||
/// Base iterator for our custom iterator based on whatever the const_iterator
|
||||
/// is for a vector of symbols.
|
||||
/// As of writing this, std::vector<elf_symbol_sptr>::const_iterator.
|
||||
typedef elf_symbols::const_iterator base_iterator;
|
||||
using base_iterator = elf_symbols::const_iterator;
|
||||
|
||||
/// An iterator to walk a vector of elf_symbols filtered by symtab_filter.
|
||||
///
|
||||
@@ -110,11 +110,12 @@ typedef elf_symbols::const_iterator base_iterator;
|
||||
class symtab_iterator : public base_iterator
|
||||
{
|
||||
public:
|
||||
typedef base_iterator::value_type value_type;
|
||||
typedef base_iterator::reference reference;
|
||||
typedef base_iterator::pointer pointer;
|
||||
typedef base_iterator::difference_type difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
using value_type = base_iterator::value_type;
|
||||
using reference = base_iterator::reference;
|
||||
using pointer = base_iterator::pointer;
|
||||
using difference_type = base_iterator::difference_type;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
|
||||
/// Construct the iterator based on a pair of underlying iterators and a
|
||||
/// symtab_filter object. Immediately fast forward to the next element that
|
||||
@@ -172,7 +173,7 @@ private:
|
||||
|
||||
/// Convenience declaration of a unique_ptr<symtab>
|
||||
class symtab;
|
||||
typedef std::unique_ptr<symtab> symtab_ptr;
|
||||
using symtab_ptr = std::unique_ptr<symtab>;
|
||||
|
||||
/// symtab is the actual data container of the symtab_reader implementation.
|
||||
///
|
||||
@@ -201,7 +202,7 @@ typedef std::unique_ptr<symtab> symtab_ptr;
|
||||
class symtab
|
||||
{
|
||||
public:
|
||||
typedef std::function<bool(const elf_symbol_sptr&)> symbol_predicate;
|
||||
using symbol_predicate = std::function<bool(const elf_symbol_sptr&)>;
|
||||
|
||||
/// Indicate whether any (kernel) symbols have been seen at construction.
|
||||
///
|
||||
@@ -215,7 +216,7 @@ public:
|
||||
|
||||
/// The (only) iterator type we offer is a const_iterator implemented by the
|
||||
/// symtab_iterator.
|
||||
typedef symtab_iterator const_iterator;
|
||||
using const_iterator = symtab_iterator;
|
||||
|
||||
/// Obtain an iterator to the beginning of the symtab according to the filter
|
||||
/// criteria. Whenever this iterator advances, it skips elements that do not
|
||||
@@ -271,12 +272,12 @@ private:
|
||||
bool has_ksymtab_entries_;
|
||||
|
||||
/// Lookup map name->symbol(s)
|
||||
typedef std::unordered_map<std::string, std::vector<elf_symbol_sptr>>
|
||||
name_symbol_map_type;
|
||||
using name_symbol_map_type =
|
||||
std::unordered_map<std::string, std::vector<elf_symbol_sptr>>;
|
||||
name_symbol_map_type name_symbol_map_;
|
||||
|
||||
/// Lookup map addr->symbol
|
||||
typedef std::unordered_map<GElf_Addr, elf_symbol_sptr> addr_symbol_map_type;
|
||||
using addr_symbol_map_type = std::unordered_map<GElf_Addr, elf_symbol_sptr>;
|
||||
addr_symbol_map_type addr_symbol_map_;
|
||||
|
||||
/// Lookup map function entry address -> symbol
|
||||
|
||||
+428
-42
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
///@file
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/xmlversion.h>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@@ -47,6 +48,9 @@
|
||||
#ifdef WITH_CTF
|
||||
#include "abg-ctf-reader.h"
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
#include "abg-btf-reader.h"
|
||||
#endif
|
||||
#include "abg-internal.h"
|
||||
#include "abg-regex.h"
|
||||
|
||||
@@ -73,6 +77,20 @@ using namespace abigail::ini;
|
||||
namespace tools_utils
|
||||
{
|
||||
|
||||
/// This function needs to be called before any libabigail function.
|
||||
///
|
||||
/// Users of libabigail must call it prior to using any of the
|
||||
/// functions of the library.
|
||||
///
|
||||
/// It intends to initialize the underlying libraries that might need
|
||||
/// initialization, especially, libxml2, in multi-threaded environments.
|
||||
void
|
||||
initialize()
|
||||
{
|
||||
LIBXML_TEST_VERSION;
|
||||
xmlInitParser();
|
||||
}
|
||||
|
||||
/// Get the value of $libdir variable of the autotools build
|
||||
/// system. This is where shared libraries are usually installed.
|
||||
///
|
||||
@@ -498,12 +516,40 @@ 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 (dir_contains_ctf_archive(*path, vmlinux))
|
||||
if (find_file_under_dir(*path, "vmlinux.ctfa", vmlinux))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Test if an ELF file has BTFG debug info.
|
||||
///
|
||||
/// @param elf_file_path the path to the ELF file to consider.
|
||||
///
|
||||
/// @param debug_info_root a vector of pointer to directory to look
|
||||
/// for debug info, in case the file is associated to split debug
|
||||
/// info. If there is no split debug info then this vector can be
|
||||
/// empty. Note that convert_char_stars_to_char_star_stars() can be
|
||||
/// used to ease the construction of this vector.
|
||||
///
|
||||
/// @return true iff the ELF file at @elf_file_path is an ELF file
|
||||
/// that contains debug info.
|
||||
bool
|
||||
file_has_btf_debug_info(const string& elf_file_path,
|
||||
const vector<char**>& debug_info_root_paths)
|
||||
{
|
||||
if (guess_file_type(elf_file_path) != FILE_TYPE_ELF)
|
||||
return false;
|
||||
|
||||
environment env;
|
||||
elf::reader r(elf_file_path, debug_info_root_paths, env);
|
||||
|
||||
if (r.find_btf_section())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Tests if a given path is a directory or a symbolic link to a
|
||||
/// directory.
|
||||
///
|
||||
@@ -521,16 +567,25 @@ is_dir(const string& path)
|
||||
if (S_ISDIR(st.st_mode))
|
||||
return true;
|
||||
|
||||
string symlink_target_path;
|
||||
if (maybe_get_symlink_target_file_path(path, symlink_target_path))
|
||||
return is_dir(symlink_target_path);
|
||||
if (S_ISLNK(st.st_mode))
|
||||
{
|
||||
string symlink_target_path;
|
||||
if (maybe_get_symlink_target_file_path(path, symlink_target_path))
|
||||
{
|
||||
if (!get_stat(path, &st))
|
||||
return false;
|
||||
|
||||
if (S_ISDIR(st.st_mode))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* ANONYMOUS_STRUCT_INTERNAL_NAME = "__anonymous_struct__";
|
||||
static const char* ANONYMOUS_UNION_INTERNAL_NAME = "__anonymous_union__";
|
||||
static const char* ANONYMOUS_ENUM_INTERNAL_NAME = "__anonymous_enum__";
|
||||
static const char* ANONYMOUS_STRUCT_INTERNAL_NAME = "__anonymous_struct__";
|
||||
static const char* ANONYMOUS_UNION_INTERNAL_NAME = "__anonymous_union__";
|
||||
static const char* ANONYMOUS_ENUM_INTERNAL_NAME = "__anonymous_enum__";
|
||||
static const char* ANONYMOUS_SUBRANGE_INTERNAL_NAME = "__anonymous_range__";
|
||||
|
||||
static int ANONYMOUS_STRUCT_INTERNAL_NAME_LEN =
|
||||
strlen(ANONYMOUS_STRUCT_INTERNAL_NAME);
|
||||
@@ -555,6 +610,9 @@ const char*
|
||||
get_anonymous_union_internal_name_prefix()
|
||||
{return ANONYMOUS_UNION_INTERNAL_NAME;}
|
||||
|
||||
static int ANONYMOUS_SUBRANGE_INTERNAL_NAME_LEN =
|
||||
strlen(ANONYMOUS_SUBRANGE_INTERNAL_NAME);
|
||||
|
||||
/// Getter of the prefix for the name of anonymous enums.
|
||||
///
|
||||
/// @reaturn the prefix for the name of anonymous enums.
|
||||
@@ -562,6 +620,13 @@ const char*
|
||||
get_anonymous_enum_internal_name_prefix()
|
||||
{return ANONYMOUS_ENUM_INTERNAL_NAME;}
|
||||
|
||||
/// Getter of the prefix for the name of anonymous range.
|
||||
///
|
||||
/// @reaturn the prefix for the name of anonymous range.
|
||||
const char*
|
||||
get_anonymous_subrange_internal_name_prefix()
|
||||
{return ANONYMOUS_SUBRANGE_INTERNAL_NAME;}
|
||||
|
||||
/// Compare two fully qualified decl names by taking into account that
|
||||
/// they might have compontents that are anonymous types/namespace names.
|
||||
///
|
||||
@@ -658,9 +723,6 @@ maybe_get_symlink_target_file_path(const string& file_path,
|
||||
if (!get_stat(file_path, &st))
|
||||
return false;
|
||||
|
||||
if (!S_ISLNK(st.st_mode))
|
||||
return false;
|
||||
|
||||
char *link_target_path = realpath(file_path.c_str(), NULL);
|
||||
if (!link_target_path)
|
||||
return false;
|
||||
@@ -1025,9 +1087,9 @@ split_string(const string& input_string,
|
||||
/// @return true iff the function could find a prefix for the suffix
|
||||
/// @p suffix in the input string @p input_string.
|
||||
bool
|
||||
string_suffix(const string& input_string,
|
||||
const string& prefix,
|
||||
string& suffix)
|
||||
string_suffix(const string& input_string,
|
||||
const string& prefix,
|
||||
string& suffix)
|
||||
{
|
||||
// Some basic sanity check before we start hostilities.
|
||||
if (prefix.length() >= input_string.length())
|
||||
@@ -1193,6 +1255,34 @@ execute_command_and_get_output(const string& cmd, vector<string>& lines)
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Get a vector of arguments from a string containing a
|
||||
/// comma-separated list of those arguments.
|
||||
///
|
||||
/// @param input_str the input string containing the comma-separated
|
||||
/// list of arguments The input string has the form
|
||||
/// "option=arg1,arg2,arg3,arg4".
|
||||
///
|
||||
/// @param option if the content of the input string @p input_str is
|
||||
/// "option=arg1,arg2,arg3", then this parameter should be "option".
|
||||
///
|
||||
/// @param arguments this is set by the fonction the the arguments
|
||||
/// that were a comma-separated list of arguments on the right hand
|
||||
/// side of the '=' sign in the string @p input_str.
|
||||
void
|
||||
get_comma_separated_args_of_option(const string& input_str,
|
||||
const string& option,
|
||||
vector<string>& arguments)
|
||||
{
|
||||
string s = input_str;
|
||||
|
||||
string_suffix(s, option, s);
|
||||
if (string_begins_with(s, "\""))
|
||||
s = s.substr(1);
|
||||
if (string_ends_with(s, "\""))
|
||||
s = s.substr(0, s.size() - 1);
|
||||
split_string(s, ",", arguments);
|
||||
}
|
||||
|
||||
/// Get the SONAMEs of the DSOs advertised as being "provided" by a
|
||||
/// given RPM. That set can be considered as being the set of
|
||||
/// "public" DSOs of the RPM.
|
||||
@@ -1733,34 +1823,64 @@ get_rpm_arch(const string& str, string& arch)
|
||||
|
||||
/// Tests if a given file name designates a kernel package.
|
||||
///
|
||||
/// @param file_name the file name to consider.
|
||||
/// @param file_path the path to the file to consider.
|
||||
///
|
||||
/// @param file_type the type of the file @p file_name.
|
||||
///
|
||||
/// @return true iff @p file_name of kind @p file_type designates a
|
||||
/// kernel package.
|
||||
bool
|
||||
file_is_kernel_package(const string& file_name, file_type file_type)
|
||||
file_is_kernel_package(const string& file_path, file_type file_type)
|
||||
{
|
||||
bool result = false;
|
||||
string package_name;
|
||||
|
||||
if (file_type == FILE_TYPE_RPM)
|
||||
{
|
||||
if (!get_rpm_name(file_name, package_name))
|
||||
return false;
|
||||
result = (package_name == "kernel");
|
||||
if (rpm_contains_file(file_path, "vmlinuz"))
|
||||
result = true;
|
||||
}
|
||||
else if (file_type == FILE_TYPE_DEB)
|
||||
{
|
||||
if (!get_deb_name(file_name, package_name))
|
||||
return false;
|
||||
result = (string_begins_with(package_name, "linux-image"));
|
||||
string file_name;
|
||||
base_name(file_path, file_name);
|
||||
string package_name;
|
||||
if (get_deb_name(file_name, package_name))
|
||||
result = (string_begins_with(package_name, "linux-image"));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Test if an RPM package contains a given file.
|
||||
///
|
||||
/// @param rpm_path the path to the RPM package.
|
||||
///
|
||||
/// @param file_name the file name to test the presence for in the
|
||||
/// rpm.
|
||||
///
|
||||
/// @return true iff the file named @file_name is present in the RPM.
|
||||
bool
|
||||
rpm_contains_file(const string& rpm_path, const string& file_name)
|
||||
{
|
||||
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
|
||||
// valid output or not.
|
||||
execute_command_and_get_output("rpm -qlp "
|
||||
+ rpm_path + " 2> /dev/null",
|
||||
query_output);
|
||||
|
||||
for (auto& line : query_output)
|
||||
{
|
||||
line = trim_white_space(line);
|
||||
if (string_ends_with(line, file_name))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Tests if a given file name designates a kernel debuginfo package.
|
||||
///
|
||||
/// @param file_name the file name to consider.
|
||||
@@ -2090,7 +2210,8 @@ gen_suppr_spec_from_kernel_abi_whitelists
|
||||
++section_iter)
|
||||
{
|
||||
std::string section_name = (*section_iter)->get_name();
|
||||
if (!string_ends_with(section_name, "whitelist"))
|
||||
if (!string_ends_with(section_name, "whitelist")
|
||||
&& !string_ends_with(section_name, "stablelist"))
|
||||
continue;
|
||||
for (ini::config::properties_type::const_iterator
|
||||
prop_iter = (*section_iter)->get_properties().begin(),
|
||||
@@ -2229,13 +2350,20 @@ load_default_user_suppressions(suppr::suppressions_type& supprs)
|
||||
///
|
||||
/// @param entry the FTSENT* to consider.
|
||||
///
|
||||
/// @param fname the file name (or end of path) to consider.
|
||||
/// @param fname the file name (or end of path) to consider. The file
|
||||
/// name can also be a path that is relative to the root directory the
|
||||
/// current visit is started from. The root directory is given by @p
|
||||
/// root_dir.
|
||||
///
|
||||
/// @param root_dir the root dir from which the directory visit is
|
||||
/// being performed.
|
||||
///
|
||||
/// @return true iff @p entry denotes a file which path ends with @p
|
||||
/// fname.
|
||||
static bool
|
||||
entry_of_file_with_name(const FTSENT *entry,
|
||||
const string& fname)
|
||||
const string& fname,
|
||||
const string& root_dir)
|
||||
{
|
||||
if (entry == NULL
|
||||
|| (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
|
||||
@@ -2246,6 +2374,11 @@ entry_of_file_with_name(const FTSENT *entry,
|
||||
string fpath = ::basename(entry->fts_path);
|
||||
if (fpath == fname)
|
||||
return true;
|
||||
|
||||
fpath = trim_leading_string(entry->fts_path, root_dir);
|
||||
if (fpath == fname)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2271,25 +2404,240 @@ find_file_under_dir(const string& root_dir,
|
||||
if (!file_hierarchy)
|
||||
return false;
|
||||
|
||||
string r = root_dir;
|
||||
if (!string_ends_with(r, "/"))
|
||||
r += "/";
|
||||
|
||||
FTSENT *entry;
|
||||
while ((entry = fts_read(file_hierarchy)))
|
||||
{
|
||||
if (entry_of_file_with_name(entry, file_path_to_look_for, r))
|
||||
{
|
||||
result = entry->fts_path;
|
||||
return true;
|
||||
}
|
||||
// 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 (entry_of_file_with_name(entry, file_path_to_look_for))
|
||||
{
|
||||
result = entry->fts_path;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fts_close(file_hierarchy);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Find a given file possibly under a set of directories and return
|
||||
/// its absolute path.
|
||||
///
|
||||
/// @param root_dirs the vector of root directories under which to
|
||||
/// look for.
|
||||
///
|
||||
/// @param file_path_to_look_for the file to look for under the
|
||||
/// directory @p root_dir.
|
||||
///
|
||||
/// @param result the resulting path to @p file_path_to_look_for.
|
||||
/// This is set iff the file has been found.
|
||||
bool
|
||||
find_file_under_dirs(const vector<string>& root_dirs,
|
||||
const string& file_path_to_look_for,
|
||||
string& result)
|
||||
{
|
||||
if (root_dirs.empty())
|
||||
return find_file_under_dir(".", file_path_to_look_for, result);
|
||||
|
||||
for (const auto& root_dir : root_dirs)
|
||||
if (find_file_under_dir(root_dir, file_path_to_look_for, result))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Get the dependencies of an ABI corpus, which are found in a set of
|
||||
/// directories. Note that the dependencies are listed as properties
|
||||
/// of the ABI corpus.
|
||||
///
|
||||
/// If the corpus has a dependency that is not found under any of the
|
||||
/// given directories, then the dependency is ignored and not
|
||||
/// returned.
|
||||
///
|
||||
/// @param korpus the ABI corpus to consider.
|
||||
///
|
||||
/// @param deps_dirs the list of directories where to look for the
|
||||
/// dependencies.
|
||||
///
|
||||
/// @param dependencies output parameter that is set the dependencies
|
||||
/// of the corpus denoted by @p korpus which are found in the
|
||||
/// directories @p deps_dirs. This is set iff the function returns
|
||||
/// true.
|
||||
///
|
||||
/// @return true iff some dependencies of the corpus @p korpus were
|
||||
/// found in directories @p deps_dirs.
|
||||
bool
|
||||
get_dependencies(const corpus& korpus,
|
||||
const vector<string>& deps_dirs,
|
||||
set<string>& dependencies)
|
||||
{
|
||||
const vector<string>& set_of_needed = korpus.get_needed();
|
||||
if (set_of_needed.empty())
|
||||
return false;
|
||||
|
||||
bool found_at_least_one_dependency =false;
|
||||
for (const auto& n :set_of_needed)
|
||||
{
|
||||
string dependency;
|
||||
if (dependencies.find(n) == dependencies.end()
|
||||
&& find_file_under_dirs(deps_dirs, n, dependency))
|
||||
{
|
||||
dependencies.insert(dependency);
|
||||
found_at_least_one_dependency = true;
|
||||
}
|
||||
}
|
||||
|
||||
return found_at_least_one_dependency;
|
||||
}
|
||||
|
||||
/// For each binary of a vector of binaries, if the binary is present
|
||||
/// in at least one of the directories listed in a given vector,
|
||||
/// construct a corpus and add it to a corpus group.
|
||||
///
|
||||
/// @param reader the reader used to read the binaries into an ABI corpus.
|
||||
///
|
||||
/// @param binaries the vector of binaries to read and add to a corpus
|
||||
/// group.
|
||||
///
|
||||
/// @param deps_dirs the vector of directories where to look for the
|
||||
/// binaries in @p binaries.
|
||||
///
|
||||
/// @param group the corpus group to add the corpus.
|
||||
void
|
||||
add_binaries_into_corpus_group(const fe_iface_sptr& reader,
|
||||
const vector<string>& binaries,
|
||||
const vector<string>& deps_dirs,
|
||||
corpus_group& group)
|
||||
{
|
||||
vector<string> bins;
|
||||
|
||||
for (const auto& b : binaries)
|
||||
{
|
||||
string bin;
|
||||
if (find_file_under_dirs(deps_dirs, b, bin))
|
||||
bins.push_back(bin);
|
||||
}
|
||||
|
||||
for (const auto& b : bins)
|
||||
{
|
||||
if (group.has_corpus(b))
|
||||
continue;
|
||||
|
||||
reader->initialize(b);
|
||||
fe_iface::status stat = fe_iface::STATUS_UNKNOWN;
|
||||
corpus_sptr c = reader->read_corpus(stat);
|
||||
if (c && (stat & fe_iface::STATUS_OK))
|
||||
group.add_corpus(c);
|
||||
}
|
||||
}
|
||||
|
||||
/// For each dependency of a given corpus, if it is present in at
|
||||
/// least one of the directories listed in a given vector, construct a
|
||||
/// corpus and add it to a corpus group.
|
||||
///
|
||||
/// @param reader the reader used to read the binaries into an ABI corpus.
|
||||
///
|
||||
/// @param korpus the corpus to consider.
|
||||
///
|
||||
/// @param deps_dirs the vector of directories where to look for the
|
||||
/// dependencies of @p korpus.
|
||||
///
|
||||
/// @param group the corpus group to add the corpus.
|
||||
void
|
||||
add_dependencies_into_corpus_group(const fe_iface_sptr& reader,
|
||||
const corpus& korpus,
|
||||
const vector<string>& deps_dirs,
|
||||
corpus_group& group)
|
||||
|
||||
{
|
||||
set<string> deps;
|
||||
if (!get_dependencies(korpus, deps_dirs, deps))
|
||||
return;
|
||||
|
||||
for (const auto& dep: deps)
|
||||
{
|
||||
if (group.has_corpus(dep))
|
||||
continue;
|
||||
|
||||
reader->initialize(dep);
|
||||
fe_iface::status stat = fe_iface::STATUS_UNKNOWN;
|
||||
corpus_sptr c = reader->read_corpus(stat);
|
||||
if (c && (stat & fe_iface::STATUS_OK))
|
||||
{
|
||||
group.add_corpus(c);
|
||||
add_dependencies_into_corpus_group(reader, *c, deps_dirs, group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a corpus group made of a given korpus and a set of binaries
|
||||
/// found in a set of directories.
|
||||
///
|
||||
/// @param reader the reader to use to read the binaries.
|
||||
///
|
||||
/// @param korpus the ABI corpus to add to the corpus group.
|
||||
///
|
||||
/// @param binaries the set of binaries to add to the corpus group, if
|
||||
/// they are present one of the directories denoted by the vector @p
|
||||
/// deps_dirs.
|
||||
///
|
||||
/// @param bins_dirs the directories where the binaries listed in @p
|
||||
/// binaries are to be found.
|
||||
///
|
||||
/// @return a corpus group made of @p korpus and the binaries listed
|
||||
/// in @p binaries and found in at least one of the directories found
|
||||
/// in @p bins_dirs.
|
||||
corpus_group_sptr
|
||||
stick_corpus_and_binaries_into_corpus_group(const fe_iface_sptr& reader,
|
||||
const corpus_sptr& korpus,
|
||||
const vector<string>& binaries,
|
||||
const vector<string>& bins_dirs)
|
||||
{
|
||||
corpus_group_sptr result (new corpus_group(korpus->get_environment(),
|
||||
korpus->get_path()));
|
||||
result->add_corpus(korpus);
|
||||
|
||||
add_binaries_into_corpus_group(reader, binaries, bins_dirs, *result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Create a corpus group made of a given korpus and the subset of its
|
||||
/// dependencies that can be found found in a set of directories.
|
||||
///
|
||||
/// @param reader the reader to use to read the binaries.
|
||||
///
|
||||
/// @param korpus the ABI corpus to add to the corpus group along with
|
||||
/// its dependencies that can be found in a subset of directories.
|
||||
///
|
||||
/// @param deps_dirs the directories where the dependencies of the ABI
|
||||
/// corpus denoted by @p korpus binaries are to be found.
|
||||
///
|
||||
/// @return a corpus group made of @p korpus and the subset of its
|
||||
/// dependencies found in at least one of the directories denoted by
|
||||
/// @p deps_dirs.
|
||||
corpus_group_sptr
|
||||
stick_corpus_and_dependencies_into_corpus_group(const fe_iface_sptr& reader,
|
||||
const corpus_sptr& korpus,
|
||||
const vector<string>& deps_dirs)
|
||||
{
|
||||
corpus_group_sptr result (new corpus_group(korpus->get_environment(),
|
||||
korpus->get_path()));
|
||||
result->add_corpus(korpus);
|
||||
|
||||
add_dependencies_into_corpus_group(reader, *korpus, deps_dirs, *result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// If we were given suppression specification files or kabi whitelist
|
||||
/// files, this function parses those, come up with suppression
|
||||
/// specifications as a result, and set them to the read context.
|
||||
@@ -2310,10 +2658,10 @@ find_file_under_dir(const string& root_dir,
|
||||
///
|
||||
/// @param opts the options to consider.
|
||||
static void
|
||||
load_generate_apply_suppressions(elf_based_reader &rdr,
|
||||
vector<string>& suppr_paths,
|
||||
vector<string>& kabi_whitelist_paths,
|
||||
suppressions_type& supprs)
|
||||
load_generate_apply_suppressions(elf_based_reader& rdr,
|
||||
vector<string>& suppr_paths,
|
||||
vector<string>& kabi_whitelist_paths,
|
||||
suppressions_type& supprs)
|
||||
{
|
||||
if (supprs.empty())
|
||||
{
|
||||
@@ -2511,19 +2859,29 @@ get_binary_paths_from_kernel_dist(const string& dist_root,
|
||||
string debug_info_root;
|
||||
if (dir_exists(dist_root + "/lib/modules"))
|
||||
{
|
||||
dist_root + "/lib/modules";
|
||||
kernel_modules_root = dist_root + "/lib/modules";
|
||||
debug_info_root = debug_info_root_path.empty()
|
||||
? dist_root
|
||||
? dist_root + "/usr/lib/debug"
|
||||
: debug_info_root_path;
|
||||
debug_info_root += "/usr/lib/debug";
|
||||
}
|
||||
|
||||
if (dir_is_empty(debug_info_root))
|
||||
debug_info_root.clear();
|
||||
|
||||
bool found = false;
|
||||
string from = dist_root;
|
||||
if (find_vmlinux_and_module_paths(from, vmlinux_path, module_paths))
|
||||
// If vmlinux_path is empty, we want to look for it under
|
||||
// debug_info_root, because this is where Enterprise Linux packages
|
||||
// put it. Modules however are to be looked for under
|
||||
// kernel_modules_root.
|
||||
if (// So, Let's look for modules under kernel_modules_root ...
|
||||
find_vmlinux_and_module_paths(kernel_modules_root,
|
||||
vmlinux_path,
|
||||
module_paths)
|
||||
// ... and if vmlinux_path is empty, look for vmlinux under the
|
||||
// debug info root.
|
||||
|| find_vmlinux_and_module_paths(debug_info_root,
|
||||
vmlinux_path,
|
||||
module_paths))
|
||||
found = true;
|
||||
|
||||
std::sort(module_paths.begin(), module_paths.end());
|
||||
@@ -2761,7 +3119,10 @@ build_corpus_group_from_kernel_dist_under(const string& root,
|
||||
|
||||
if (verbose)
|
||||
std::cerr << "Analysing kernel dist root '"
|
||||
<< root << "' ... " << std::flush;
|
||||
<< root
|
||||
<< "' with vmlinux path: '"
|
||||
<< vmlinux_path
|
||||
<< "' ... " << std::flush;
|
||||
|
||||
timer t;
|
||||
|
||||
@@ -2781,6 +3142,16 @@ build_corpus_group_from_kernel_dist_under(const string& root,
|
||||
vector<char**> di_roots;
|
||||
di_roots.push_back(&di_root_ptr);
|
||||
|
||||
#ifdef WITH_CTF
|
||||
shared_ptr<char> 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);
|
||||
}
|
||||
#endif
|
||||
|
||||
abigail::elf_based_reader_sptr reader =
|
||||
create_best_elf_based_reader(vmlinux,
|
||||
di_roots,
|
||||
@@ -2850,6 +3221,13 @@ create_best_elf_based_reader(const string& elf_file_path,
|
||||
#ifdef WITH_CTF
|
||||
if (file_has_ctf_debug_info(elf_file_path, debug_info_root_paths))
|
||||
result = ctf::create_reader(elf_file_path, debug_info_root_paths, env);
|
||||
#endif
|
||||
}
|
||||
else if (requested_fe_kind & corpus::BTF_ORIGIN)
|
||||
{
|
||||
#ifdef WITH_BTF
|
||||
if (file_has_btf_debug_info(elf_file_path, debug_info_root_paths))
|
||||
result = btf::create_reader(elf_file_path, debug_info_root_paths, env);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@@ -2862,6 +3240,14 @@ create_best_elf_based_reader(const string& elf_file_path,
|
||||
// front end even if it wasn't formally requested by the user.
|
||||
result = ctf::create_reader(elf_file_path, debug_info_root_paths, env);
|
||||
#endif
|
||||
|
||||
#ifdef WITH_BTF
|
||||
if (!file_has_dwarf_debug_info(elf_file_path, debug_info_root_paths)
|
||||
&& file_has_btf_debug_info(elf_file_path, debug_info_root_paths))
|
||||
// The file has BTF debug info and no BTF, let's use the BTF
|
||||
// front-end even if it wasn't formally requested by the user.
|
||||
result = btf::create_reader(elf_file_path, debug_info_root_paths, env);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!result)
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 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-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 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-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 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-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
|
||||
+83
-30
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
|
||||
/// @file
|
||||
///
|
||||
@@ -230,7 +230,8 @@ class write_context
|
||||
class_tmpl_shared_ptr_map m_class_tmpl_id_map;
|
||||
string_elf_symbol_sptr_map_type m_fun_symbol_map;
|
||||
string_elf_symbol_sptr_map_type m_var_symbol_map;
|
||||
unordered_set<interned_string, hash_interned_string> m_emitted_decls_set;
|
||||
unordered_set<interned_string, hash_interned_string> m_emitted_decls_set;
|
||||
unordered_set<string> m_emitted_corpora_set;
|
||||
|
||||
write_context();
|
||||
|
||||
@@ -818,6 +819,42 @@ public:
|
||||
m_emitted_decls_set.insert(irepr);
|
||||
}
|
||||
|
||||
/// Test if a corpus has already been emitted.
|
||||
///
|
||||
/// A corpus is emitted if it's been recorded as having been emitted
|
||||
/// by the function record_corpus_as_emitted().
|
||||
///
|
||||
/// @param corp the corpus to consider.
|
||||
///
|
||||
/// @return true iff the corpus @p corp has been emitted.
|
||||
bool
|
||||
corpus_is_emitted(const corpus_sptr& corp)
|
||||
{
|
||||
if (!corp)
|
||||
return false;
|
||||
|
||||
if (m_emitted_corpora_set.find(corp->get_path())
|
||||
== m_emitted_corpora_set.end())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Record the corpus has having been emitted.
|
||||
///
|
||||
/// @param corp the corpus to consider.
|
||||
void
|
||||
record_corpus_as_emitted(const corpus_sptr& corp)
|
||||
{
|
||||
if (!corp)
|
||||
return;
|
||||
|
||||
const string& path = corp->get_path();
|
||||
ABG_ASSERT(!path.empty());
|
||||
|
||||
m_emitted_corpora_set.insert(path);
|
||||
}
|
||||
|
||||
/// Get the set of types that have been emitted.
|
||||
///
|
||||
/// @return the set of types that have been emitted.
|
||||
@@ -884,6 +921,9 @@ static bool write_reference_type_def(const reference_type_def_sptr&,
|
||||
write_context&, unsigned);
|
||||
static bool write_array_type_def(const array_type_def_sptr&,
|
||||
write_context&, unsigned);
|
||||
static bool write_array_subrange_type(const array_type_def::subrange_sptr&,
|
||||
write_context&,
|
||||
unsigned);
|
||||
static bool write_enum_type_decl(const enum_type_decl_sptr&,
|
||||
write_context&, unsigned);
|
||||
static bool write_typedef_decl(const typedef_decl_sptr&,
|
||||
@@ -1470,7 +1510,7 @@ static void
|
||||
write_array_size_and_alignment(const shared_ptr<array_type_def> decl, ostream& o)
|
||||
{
|
||||
if (decl->is_infinite())
|
||||
o << " size-in-bits='" << "infinite" << "'";
|
||||
o << " size-in-bits='" << "unknown" << "'";
|
||||
else {
|
||||
size_t size_in_bits = decl->get_size_in_bits();
|
||||
if (size_in_bits)
|
||||
@@ -1932,6 +1972,9 @@ write_decl(const decl_base_sptr& decl, write_context& ctxt, unsigned indent)
|
||||
<reference_type_def>(decl), ctxt, indent)
|
||||
|| write_array_type_def(dynamic_pointer_cast
|
||||
<array_type_def>(decl), ctxt, indent)
|
||||
|| write_array_subrange_type(dynamic_pointer_cast
|
||||
<array_type_def::subrange_type>(decl),
|
||||
ctxt, indent)
|
||||
|| write_enum_type_decl(dynamic_pointer_cast<enum_type_decl>(decl),
|
||||
ctxt, indent)
|
||||
|| write_typedef_decl(dynamic_pointer_cast<typedef_decl>(decl),
|
||||
@@ -2698,15 +2741,19 @@ write_pointer_type_def(const pointer_type_def_sptr& decl,
|
||||
|
||||
ostream& o = ctxt.get_ostream();
|
||||
|
||||
annotate(decl, ctxt, indent);
|
||||
|
||||
do_indent(o, indent);
|
||||
|
||||
string i;
|
||||
|
||||
o << "<pointer-type-def ";
|
||||
|
||||
type_base_sptr pointed_to_type = decl->get_pointed_to_type();
|
||||
|
||||
annotate(decl->get_canonical_type(), ctxt, indent);
|
||||
i = ctxt.get_id_for_type(pointed_to_type);
|
||||
|
||||
do_indent(o, indent);
|
||||
o << "<pointer-type-def type-id='"
|
||||
<< ctxt.get_id_for_type(pointed_to_type)
|
||||
<< "'";
|
||||
o << "type-id='" << i << "'";
|
||||
|
||||
ctxt.record_type_as_referenced(pointed_to_type);
|
||||
|
||||
@@ -2716,7 +2763,7 @@ write_pointer_type_def(const pointer_type_def_sptr& decl,
|
||||
: decl->get_translation_unit()->get_address_size()),
|
||||
0);
|
||||
|
||||
string i = id;
|
||||
i = id;
|
||||
if (i.empty())
|
||||
i = ctxt.get_id_for_type(decl);
|
||||
|
||||
@@ -2857,21 +2904,19 @@ write_array_subrange_type(const array_type_def::subrange_sptr& decl,
|
||||
|
||||
o << " length='";
|
||||
if (decl->is_infinite())
|
||||
o << "infinite";
|
||||
o << "unknown";
|
||||
else
|
||||
o << decl->get_length();
|
||||
|
||||
o << "'";
|
||||
|
||||
if (decl->get_lower_bound())
|
||||
{
|
||||
ABG_ASSERT(decl->is_infinite()
|
||||
|| (decl->get_length() ==
|
||||
(uint64_t) (decl->get_upper_bound()
|
||||
- decl->get_lower_bound() + 1)));
|
||||
o << " lower-bound='" << decl->get_lower_bound() << "' upper-bound='"
|
||||
<< decl->get_upper_bound() << "'";
|
||||
}
|
||||
ABG_ASSERT(decl->is_infinite()
|
||||
|| decl->get_length() == 0
|
||||
|| (decl->get_length() ==
|
||||
(uint64_t) (decl->get_upper_bound()
|
||||
- decl->get_lower_bound() + 1)));
|
||||
o << " lower-bound='" << decl->get_lower_bound() << "' upper-bound='"
|
||||
<< decl->get_upper_bound() << "'";
|
||||
|
||||
type_base_sptr underlying_type = decl->get_underlying_type();
|
||||
if (underlying_type)
|
||||
@@ -4588,6 +4633,7 @@ write_corpus(write_context& ctxt,
|
||||
out << "</abi-corpus>\n";
|
||||
|
||||
ctxt.clear_referenced_types();
|
||||
ctxt.record_corpus_as_emitted(corpus);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -4639,7 +4685,10 @@ std::ostream& out = ctxt.get_ostream();
|
||||
group->get_corpora().begin();
|
||||
c != group->get_corpora().end();
|
||||
++c)
|
||||
write_corpus(ctxt, *c, get_indent_to_level(ctxt, indent, 1), true);
|
||||
{
|
||||
ABG_ASSERT(!ctxt.corpus_is_emitted(*c));
|
||||
write_corpus(ctxt, *c, get_indent_to_level(ctxt, indent, 1), true);
|
||||
}
|
||||
|
||||
do_indent_to_level(ctxt, indent, 0);
|
||||
out << "</abi-corpus-group>\n";
|
||||
@@ -4861,16 +4910,20 @@ write_type_record(xml_writer::write_context& ctxt,
|
||||
// <c>0x25f9ba8</c>
|
||||
// </type>
|
||||
|
||||
string id = ctxt.get_id_for_type (const_cast<type_base*>(type));
|
||||
o << " <type>\n"
|
||||
<< " <id>" << id << "</id>\n"
|
||||
<< " <c>"
|
||||
<< std::hex
|
||||
<< (type->get_canonical_type()
|
||||
? reinterpret_cast<uintptr_t>(type->get_canonical_type().get())
|
||||
: 0xdeadbabe)
|
||||
<< "</c>\n"
|
||||
<< " </type>\n";
|
||||
type_base* canonical = type->get_naked_canonical_type();
|
||||
string id ;
|
||||
if (canonical)
|
||||
{
|
||||
id = ctxt.get_id_for_type (const_cast<type_base*>(type));
|
||||
|
||||
o << " <type>\n"
|
||||
<< " <id>" << id << "</id>\n"
|
||||
<< " <c>"
|
||||
<< std::hex
|
||||
<< reinterpret_cast<uintptr_t>(canonical)
|
||||
<< "</c>\n"
|
||||
<< " </type>\n";
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize the map that is stored at
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2014-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2014-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
|
||||
+482
-48
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include "abg-config.h"
|
||||
#include "abg-comp-filter.h"
|
||||
#include "abg-suppression.h"
|
||||
@@ -23,7 +24,12 @@
|
||||
#include "abg-ctf-reader.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_BTF
|
||||
#include "abg-btf-reader.h"
|
||||
#endif
|
||||
|
||||
using std::vector;
|
||||
using std::set;
|
||||
using std::string;
|
||||
using std::ostream;
|
||||
using std::cout;
|
||||
@@ -56,6 +62,10 @@ using abigail::tools_utils::load_default_system_suppressions;
|
||||
using abigail::tools_utils::load_default_user_suppressions;
|
||||
using abigail::tools_utils::abidiff_status;
|
||||
using abigail::tools_utils::create_best_elf_based_reader;
|
||||
using abigail::tools_utils::stick_corpus_and_dependencies_into_corpus_group;
|
||||
using abigail::tools_utils::stick_corpus_and_binaries_into_corpus_group;
|
||||
using abigail::tools_utils::add_dependencies_into_corpus_group;
|
||||
using abigail::tools_utils::get_dependencies;
|
||||
|
||||
using namespace abigail;
|
||||
|
||||
@@ -110,6 +120,9 @@ struct options
|
||||
bool show_impacted_interfaces;
|
||||
bool assume_odr_for_cplusplus;
|
||||
bool leverage_dwarf_factorization;
|
||||
bool perform_change_categorization;
|
||||
bool follow_dependencies;
|
||||
bool list_dependencies;
|
||||
bool dump_diff_tree;
|
||||
bool show_stats;
|
||||
bool do_log;
|
||||
@@ -121,11 +134,18 @@ struct options
|
||||
#endif
|
||||
#ifdef WITH_CTF
|
||||
bool use_ctf;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
bool use_btf;
|
||||
#endif
|
||||
vector<char*> di_root_paths1;
|
||||
vector<char*> di_root_paths2;
|
||||
vector<char**> prepared_di_root_paths1;
|
||||
vector<char**> prepared_di_root_paths2;
|
||||
vector<string> added_bins_dirs1;
|
||||
vector<string> added_bins_dirs2;
|
||||
vector<string> added_bins1;
|
||||
vector<string> added_bins2;
|
||||
|
||||
options()
|
||||
: display_usage(),
|
||||
@@ -163,13 +183,12 @@ struct options
|
||||
show_impacted_interfaces(),
|
||||
assume_odr_for_cplusplus(true),
|
||||
leverage_dwarf_factorization(true),
|
||||
perform_change_categorization(true),
|
||||
follow_dependencies(),
|
||||
list_dependencies(),
|
||||
dump_diff_tree(),
|
||||
show_stats(),
|
||||
do_log()
|
||||
#ifdef WITH_CTF
|
||||
,
|
||||
use_ctf()
|
||||
#endif
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
,
|
||||
do_debug_self_comparison()
|
||||
@@ -177,6 +196,14 @@ struct options
|
||||
#ifdef WITH_DEBUG_TYPE_CANONICALIZATION
|
||||
,
|
||||
do_debug_type_canonicalization()
|
||||
#endif
|
||||
#ifdef WITH_CTF
|
||||
,
|
||||
use_ctf()
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
,
|
||||
use_btf()
|
||||
#endif
|
||||
{}
|
||||
|
||||
@@ -211,6 +238,15 @@ display_usage(const string& prog_name, ostream& out)
|
||||
<< " --header-file1|--hf1 <path> the path to one header of file1\n"
|
||||
<< " --headers-dir2|--hd2 <path> the path to headers of file2\n"
|
||||
<< " --header-file2|--hf2 <path> the path to one header of file2\n"
|
||||
<< " --added-binaries-dir1 the path to the dependencies of file1\n"
|
||||
<< " --added-binaries-dir2 the path to the dependencies of file2\n"
|
||||
<< " --add-binaries1 <bin1,bin2,.>. build corpus groups with "
|
||||
"extra binaries added to the first one and compare them\n"
|
||||
<< " --add-binaries2 <bin1,bin2,..> build corpus groups with "
|
||||
"extra binaries added to the second one and compare them\n"
|
||||
<< " --follow-dependencies|--fdeps build corpus groups with the "
|
||||
"dependencies of the input files\n"
|
||||
<< " --list-dependencies|--ldeps show the dependencies of the input files\n"
|
||||
<< " --drop-private-types drop private types from "
|
||||
"internal representation\n"
|
||||
<< " --exported-interfaces-only analyze exported interfaces only\n"
|
||||
@@ -265,6 +301,8 @@ display_usage(const string& prog_name, ostream& out)
|
||||
<< " --impacted-interfaces display interfaces impacted by leaf changes\n"
|
||||
<< " --no-leverage-dwarf-factorization do not use DWZ optimisations to "
|
||||
"speed-up the analysis of the binary\n"
|
||||
<< " --no-change-categorization | -x don't perform categorization "
|
||||
"of changes, for speed purposes\n"
|
||||
<< " --no-assume-odr-for-cplusplus do not assume the ODR to speed-up the "
|
||||
"analysis of the binary\n"
|
||||
<< " --dump-diff-tree emit a debug dump of the internal diff tree to "
|
||||
@@ -273,6 +311,9 @@ display_usage(const string& prog_name, ostream& out)
|
||||
#ifdef WITH_CTF
|
||||
<< " --ctf use CTF instead of DWARF in ELF files\n"
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
<< " --btf use BTF instead of DWARF in ELF files\n"
|
||||
#endif
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
<< " --debug-self-comparison debug the process of comparing "
|
||||
"an ABI corpus against itself"
|
||||
@@ -405,6 +446,80 @@ parse_command_line(int argc, char* argv[], options& opts)
|
||||
opts.header_files2.push_back(argv[j]);
|
||||
++i;
|
||||
}
|
||||
else if (!strcmp(argv[i], "--follow-dependencies")
|
||||
|| !strcmp(argv[i], "--fdeps"))
|
||||
opts.follow_dependencies = true;
|
||||
else if (!strcmp(argv[i], "--list-dependencies")
|
||||
|| !strcmp(argv[i], "--ldeps"))
|
||||
opts.list_dependencies = true;
|
||||
else if (!strcmp(argv[i], "--added-binaries-dir1")
|
||||
|| !strcmp(argv[i], "--abd1"))
|
||||
{
|
||||
int j = i + 1;
|
||||
if (j >= argc)
|
||||
{
|
||||
opts.missing_operand = true;
|
||||
opts.wrong_option = argv[i];
|
||||
return true;
|
||||
}
|
||||
opts.added_bins_dirs1.push_back(argv[j]);
|
||||
++i;
|
||||
}
|
||||
else if (!strcmp(argv[i], "--added-binaries-dir2")
|
||||
|| !strcmp(argv[i], "--abd2"))
|
||||
{
|
||||
int j = i + 1;
|
||||
if (j >= argc)
|
||||
{
|
||||
opts.missing_operand = true;
|
||||
opts.wrong_option = argv[i];
|
||||
return true;
|
||||
}
|
||||
opts.added_bins_dirs2.push_back(argv[j]);
|
||||
++i;
|
||||
}
|
||||
else if (!strncmp(argv[i], "--add-binaries1=",
|
||||
strlen("--add-binaries1=")))
|
||||
tools_utils::get_comma_separated_args_of_option(argv[i],
|
||||
"--add-binaries1=",
|
||||
opts.added_bins1);
|
||||
else if (!strcmp(argv[i], "--add-binaries1"))
|
||||
{
|
||||
int j = i + 1;
|
||||
if (j >= argc)
|
||||
{
|
||||
opts.missing_operand = true;
|
||||
opts.wrong_option = argv[i];
|
||||
return true;
|
||||
}
|
||||
string s = argv[j];
|
||||
if (s.find(','))
|
||||
tools_utils::split_string(s, ",", opts.added_bins1);
|
||||
else
|
||||
opts.added_bins1.push_back(s);
|
||||
++i;
|
||||
}
|
||||
else if (!strncmp(argv[i], "--add-binaries2=",
|
||||
strlen("--add-binaries2=")))
|
||||
tools_utils::get_comma_separated_args_of_option(argv[i],
|
||||
"--add-binaries2=",
|
||||
opts.added_bins2);
|
||||
else if (!strcmp(argv[i], "--add-binaries2"))
|
||||
{
|
||||
int j = i + 1;
|
||||
if (j >= argc)
|
||||
{
|
||||
opts.missing_operand = true;
|
||||
opts.wrong_option = argv[i];
|
||||
return true;
|
||||
}
|
||||
string s = argv[j];
|
||||
if (s.find(','))
|
||||
tools_utils::split_string(s, ",", opts.added_bins2);
|
||||
else
|
||||
opts.added_bins2.push_back(s);
|
||||
++i;
|
||||
}
|
||||
else if (!strcmp(argv[i], "--kmi-whitelist")
|
||||
|| !strcmp(argv[i], "-w"))
|
||||
{
|
||||
@@ -434,6 +549,8 @@ parse_command_line(int argc, char* argv[], options& opts)
|
||||
opts.exported_interfaces_only = true;
|
||||
else if (!strcmp(argv[i], "--allow-non-exported-interfaces"))
|
||||
opts.exported_interfaces_only = false;
|
||||
else if (!strcmp(argv[i], "--no-linux-kernel-mode"))
|
||||
opts.linux_kernel_mode = false;
|
||||
else if (!strcmp(argv[i], "--no-default-suppression"))
|
||||
opts.no_default_supprs = true;
|
||||
else if (!strcmp(argv[i], "--no-architecture"))
|
||||
@@ -625,6 +742,9 @@ parse_command_line(int argc, char* argv[], options& opts)
|
||||
opts.show_impacted_interfaces = true;
|
||||
else if (!strcmp(argv[i], "--no-leverage-dwarf-factorization"))
|
||||
opts.leverage_dwarf_factorization = false;
|
||||
else if (!strcmp(argv[i], "--no-change-categorization")
|
||||
|| !strcmp(argv[i], "-x"))
|
||||
opts.perform_change_categorization = false;
|
||||
else if (!strcmp(argv[i], "--no-assume-odr-for-cplusplus"))
|
||||
opts.leverage_dwarf_factorization = false;
|
||||
else if (!strcmp(argv[i], "--dump-diff-tree"))
|
||||
@@ -637,6 +757,10 @@ parse_command_line(int argc, char* argv[], options& opts)
|
||||
else if (!strcmp(argv[i], "--ctf"))
|
||||
opts.use_ctf = true;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
else if (!strcmp(argv[i], "--btf"))
|
||||
opts.use_btf = true;
|
||||
#endif
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
else if (!strcmp(argv[i], "--debug-self-comparison"))
|
||||
opts.do_debug_self_comparison = true;
|
||||
@@ -732,6 +856,7 @@ set_diff_context_from_opts(diff_context_sptr ctxt,
|
||||
{
|
||||
ctxt->default_output_stream(&cout);
|
||||
ctxt->error_output_stream(&cerr);
|
||||
ctxt->perform_change_categorization(opts.perform_change_categorization);
|
||||
ctxt->show_leaf_changes_only(opts.leaf_changes_only);
|
||||
ctxt->show_hex_values(opts.show_hexadecimal_values);
|
||||
ctxt->show_offsets_sizes_in_bits(opts.show_offsets_sizes_in_bits);
|
||||
@@ -810,6 +935,8 @@ set_diff_context_from_opts(diff_context_sptr ctxt,
|
||||
}
|
||||
|
||||
ctxt->dump_diff_tree(opts.dump_diff_tree);
|
||||
|
||||
ctxt->do_log(opts.do_log);
|
||||
}
|
||||
|
||||
/// Set a bunch of tunable buttons on the ELF-based reader from the
|
||||
@@ -914,7 +1041,9 @@ set_native_xml_reader_options(abigail::fe_iface& rdr,
|
||||
const options& opts)
|
||||
{
|
||||
abixml::consider_types_not_reachable_from_public_interfaces(rdr,
|
||||
opts.show_all_types);
|
||||
opts.show_all_types);
|
||||
rdr.options().do_log = opts.do_log;
|
||||
|
||||
}
|
||||
|
||||
/// Set the regex patterns describing the functions to drop from the
|
||||
@@ -1015,7 +1144,9 @@ handle_error(abigail::fe_iface::status status_code,
|
||||
const string& prog_name,
|
||||
const options& opts)
|
||||
{
|
||||
if (!(status_code & abigail::fe_iface::STATUS_OK))
|
||||
if (!(status_code & abigail::fe_iface::STATUS_OK)
|
||||
|| status_code & abigail::fe_iface::STATUS_DEBUG_INFO_NOT_FOUND
|
||||
|| status_code & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
|
||||
{
|
||||
emit_prefix(prog_name, cerr)
|
||||
<< "failed to read input file " << opts.file1 << "\n";
|
||||
@@ -1078,10 +1209,10 @@ handle_error(abigail::fe_iface::status status_code,
|
||||
emit_prefix(prog_name, cerr)
|
||||
<< "could not find the alternate debug info file";
|
||||
|
||||
if (rdr->alternate_dwarf_debug_info())
|
||||
if (!rdr->alternate_dwarf_debug_info_path().empty())
|
||||
cerr << " at: "
|
||||
<< rdr->alternate_dwarf_debug_info_path()
|
||||
<< "\n";
|
||||
<< rdr->alternate_dwarf_debug_info_path();
|
||||
cerr << "\n";
|
||||
}
|
||||
|
||||
if (status_code & abigail::fe_iface::STATUS_NO_SYMBOLS_FOUND)
|
||||
@@ -1122,6 +1253,63 @@ emit_incompatible_format_version_error_message(const string& file_path1,
|
||||
<< "'" << file_path2 << "' (" << version2 << ")\n";
|
||||
}
|
||||
|
||||
/// Display the dependencies of two corpora.
|
||||
///
|
||||
/// @param prog_name the name of the current abidiff program.
|
||||
///
|
||||
/// @param corp1 the first corpus to consider.
|
||||
///
|
||||
/// @param corp2 the second corpus to consider.
|
||||
///
|
||||
/// @param deps1 the dependencies to display.
|
||||
///
|
||||
/// @param deps2 the dependencies to display.
|
||||
static void
|
||||
display_dependencies(const string& prog_name,
|
||||
const corpus_sptr& corp1,
|
||||
const corpus_sptr& corp2,
|
||||
const set<string>& deps1,
|
||||
const set<string>& deps2)
|
||||
{
|
||||
if (deps1.empty())
|
||||
emit_prefix(prog_name, cout)
|
||||
<< "No dependencies found for '" << corp1->get_path() << "':\n";
|
||||
else
|
||||
{
|
||||
emit_prefix(prog_name, cout)
|
||||
<< "dependencies of '" << corp1->get_path() << "':\n\t";
|
||||
|
||||
int n = 0;
|
||||
for (const auto& dep : deps1)
|
||||
{
|
||||
if (n)
|
||||
cout << ", ";
|
||||
cout << dep;
|
||||
++n;
|
||||
}
|
||||
cout << "\n";
|
||||
}
|
||||
|
||||
if (deps2.empty())
|
||||
emit_prefix(prog_name, cout)
|
||||
<< "No dependencies found for '" << corp2->get_path() << "':\n";
|
||||
else
|
||||
{
|
||||
emit_prefix(prog_name, cout)
|
||||
<< "dependencies of '" << corp2->get_path() << "':\n\t";
|
||||
|
||||
int n = 0;
|
||||
for (const auto& dep : deps2)
|
||||
{
|
||||
if (n)
|
||||
cout << ", ";
|
||||
cout << dep;
|
||||
++n;
|
||||
}
|
||||
cout << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
@@ -1230,12 +1418,17 @@ main(int argc, char* argv[])
|
||||
#ifdef WITH_CTF
|
||||
if (opts.use_ctf)
|
||||
requested_fe_kind = corpus::CTF_ORIGIN;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
if (opts.use_btf)
|
||||
requested_fe_kind = corpus::BTF_ORIGIN;
|
||||
#endif
|
||||
abigail::elf_based_reader_sptr rdr =
|
||||
create_best_elf_based_reader(opts.file1,
|
||||
opts.prepared_di_root_paths1,
|
||||
env, requested_fe_kind,
|
||||
opts.show_all_types);
|
||||
opts.show_all_types,
|
||||
opts.linux_kernel_mode);
|
||||
ABG_ASSERT(rdr);
|
||||
set_generic_options(*rdr, opts);
|
||||
set_suppressions(*rdr, opts);
|
||||
@@ -1248,6 +1441,20 @@ main(int argc, char* argv[])
|
||||
return handle_error(c1_status, rdr.get(),
|
||||
argv[0], opts);
|
||||
|
||||
if (!opts.added_bins1.empty())
|
||||
g1 = stick_corpus_and_binaries_into_corpus_group(rdr, c1,
|
||||
opts.added_bins1,
|
||||
opts.added_bins_dirs1);
|
||||
if (opts.follow_dependencies)
|
||||
{
|
||||
if (g1)
|
||||
add_dependencies_into_corpus_group(rdr, *c1,
|
||||
opts.added_bins_dirs1,
|
||||
*g1);
|
||||
else
|
||||
g1 = stick_corpus_and_dependencies_into_corpus_group(rdr, c1,
|
||||
opts.added_bins_dirs1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
|
||||
@@ -1265,8 +1472,7 @@ main(int argc, char* argv[])
|
||||
case abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP:
|
||||
{
|
||||
abigail::fe_iface_sptr rdr =
|
||||
abixml::create_reader(opts.file1,
|
||||
env);
|
||||
abixml::create_reader(opts.file1, env);
|
||||
assert(rdr);
|
||||
set_suppressions(*rdr, opts);
|
||||
set_native_xml_reader_options(*rdr, opts);
|
||||
@@ -1302,12 +1508,17 @@ main(int argc, char* argv[])
|
||||
#ifdef WITH_CTF
|
||||
if (opts.use_ctf)
|
||||
requested_fe_kind = corpus::CTF_ORIGIN;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
if (opts.use_btf)
|
||||
requested_fe_kind = corpus::BTF_ORIGIN;
|
||||
#endif
|
||||
abigail::elf_based_reader_sptr rdr =
|
||||
create_best_elf_based_reader(opts.file2,
|
||||
opts.prepared_di_root_paths2,
|
||||
env, requested_fe_kind,
|
||||
opts.show_all_types);
|
||||
opts.show_all_types,
|
||||
opts.linux_kernel_mode);
|
||||
ABG_ASSERT(rdr);
|
||||
|
||||
set_generic_options(*rdr, opts);
|
||||
@@ -1320,6 +1531,21 @@ main(int argc, char* argv[])
|
||||
&& (c2_status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
|
||||
&& (c2_status & abigail::fe_iface::STATUS_DEBUG_INFO_NOT_FOUND)))
|
||||
return handle_error(c2_status, rdr.get(), argv[0], opts);
|
||||
|
||||
if (!opts.added_bins2.empty())
|
||||
g2 = stick_corpus_and_binaries_into_corpus_group(rdr, c2,
|
||||
opts.added_bins2,
|
||||
opts.added_bins_dirs2);
|
||||
if (opts.follow_dependencies)
|
||||
{
|
||||
if (g2)
|
||||
add_dependencies_into_corpus_group(rdr, *c2,
|
||||
opts.added_bins_dirs2,
|
||||
*g2);
|
||||
else
|
||||
g2 = stick_corpus_and_dependencies_into_corpus_group(rdr, c2,
|
||||
opts.added_bins_dirs2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
|
||||
@@ -1353,6 +1579,34 @@ main(int argc, char* argv[])
|
||||
break;
|
||||
}
|
||||
|
||||
if (!opts.added_bins1.empty()
|
||||
|| !opts.added_bins2.empty())
|
||||
{
|
||||
// We were requested to compare a set of binaries against
|
||||
// another set of binaries. Let's make sure we construct
|
||||
// two ABI construct groups in all cases.
|
||||
|
||||
if (!g1 && c1)
|
||||
{
|
||||
// We don't have a corpus group for the first argument.
|
||||
// Let's build one and stick the ABI corpus at hand in
|
||||
// it.
|
||||
g1.reset(new corpus_group(c1->get_environment(),
|
||||
c1->get_path()));
|
||||
g1->add_corpus(c1);
|
||||
}
|
||||
|
||||
if (!g2 && c2)
|
||||
{
|
||||
// We don't have a corpus group for the second argument.
|
||||
// Let's build one and stick the ABI corpus at hand in
|
||||
// it.
|
||||
g2.reset(new corpus_group(c2->get_environment(),
|
||||
c2->get_path()));
|
||||
g2->add_corpus(c1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!!c1 != !!c2
|
||||
|| !!t1 != !!t2
|
||||
|| !!g1 != !!g2)
|
||||
@@ -1379,43 +1633,38 @@ main(int argc, char* argv[])
|
||||
|
||||
if (t1)
|
||||
{
|
||||
tools_utils::timer t;
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.start();
|
||||
std::cerr << "Compute diff ...\n";
|
||||
}
|
||||
|
||||
translation_unit_diff_sptr diff = compute_diff(t1, t2, ctxt);
|
||||
if (diff->has_changes())
|
||||
diff->report(cout);
|
||||
}
|
||||
else if (c1)
|
||||
{
|
||||
if (opts.show_symtabs)
|
||||
|
||||
if (opts.do_log)
|
||||
{
|
||||
display_symtabs(c1, c2, cout);
|
||||
return abigail::tools_utils::ABIDIFF_OK;
|
||||
t.stop();
|
||||
std::cerr << "diff computed!:" << t << "\n";
|
||||
}
|
||||
|
||||
const auto c1_version = c1->get_format_major_version_number();
|
||||
const auto c2_version = c2->get_format_major_version_number();
|
||||
if (c1_version != c2_version)
|
||||
{
|
||||
emit_incompatible_format_version_error_message(opts.file1,
|
||||
c1_version,
|
||||
opts.file2,
|
||||
c2_version,
|
||||
argv[0]);
|
||||
return abigail::tools_utils::ABIDIFF_ERROR;
|
||||
}
|
||||
|
||||
set_corpus_keep_drop_regex_patterns(opts, c1);
|
||||
set_corpus_keep_drop_regex_patterns(opts, c2);
|
||||
|
||||
corpus_diff_sptr diff = compute_diff(c1, c2, ctxt);
|
||||
|
||||
if (diff->has_net_changes())
|
||||
status = abigail::tools_utils::ABIDIFF_ABI_CHANGE;
|
||||
|
||||
if (diff->has_incompatible_changes())
|
||||
status |= abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE;
|
||||
|
||||
if (diff->has_changes())
|
||||
diff->report(cout);
|
||||
{
|
||||
tools_utils::timer t;
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.start();
|
||||
std::cerr << "Computing the report ...\n";
|
||||
}
|
||||
|
||||
diff->report(cout);
|
||||
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.stop();
|
||||
std::cerr << "Report computed!:" << t << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (g1)
|
||||
{
|
||||
@@ -1438,17 +1687,202 @@ main(int argc, char* argv[])
|
||||
}
|
||||
|
||||
adjust_diff_context_for_kmidiff(*ctxt);
|
||||
tools_utils::timer t;
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.start();
|
||||
std::cerr << "Compute diff ...\n";
|
||||
}
|
||||
|
||||
corpus_diff_sptr diff = compute_diff(g1, g2, ctxt);
|
||||
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.stop();
|
||||
diff->do_log(true);
|
||||
std::cerr << "diff computed!:" << t << "\n";
|
||||
}
|
||||
|
||||
if (opts.do_log)
|
||||
{
|
||||
std::cerr << "Computing net changes ...\n";
|
||||
t.start();
|
||||
}
|
||||
|
||||
if (diff->has_net_changes())
|
||||
status = abigail::tools_utils::ABIDIFF_ABI_CHANGE;
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.stop();
|
||||
std::cerr << "net changes computed!: "<< t << "\n";
|
||||
}
|
||||
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.start();
|
||||
std::cerr << "Computing incompatible changes ...\n";
|
||||
}
|
||||
|
||||
if (diff->has_incompatible_changes())
|
||||
status |= abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE;
|
||||
|
||||
if (diff->has_changes())
|
||||
diff->report(cout);
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.stop();
|
||||
std::cerr << "incompatible changes computed!: "<< t << "\n";
|
||||
}
|
||||
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.start();
|
||||
std::cerr << "Computing changes ...\n";
|
||||
}
|
||||
|
||||
if (diff->has_changes())
|
||||
{
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.stop();
|
||||
std::cerr << "changes computed!: "<< t << "\n";
|
||||
}
|
||||
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.start();
|
||||
std::cerr << "Computing report ...\n";
|
||||
}
|
||||
|
||||
diff->report(cout);
|
||||
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.stop();
|
||||
std::cerr << "Report computed!:" << t << "\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.stop();
|
||||
std::cerr << "changes computed!: "<< t << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.list_dependencies)
|
||||
{
|
||||
set<string> deps1, deps2;
|
||||
get_dependencies(*c1, opts.added_bins_dirs1, deps1);
|
||||
get_dependencies(*c2, opts.added_bins_dirs2, deps2);
|
||||
display_dependencies(argv[0], c1, c2, deps1, deps2);
|
||||
}
|
||||
}
|
||||
else if (c1)
|
||||
{
|
||||
if (opts.show_symtabs)
|
||||
{
|
||||
display_symtabs(c1, c2, cout);
|
||||
return abigail::tools_utils::ABIDIFF_OK;
|
||||
}
|
||||
|
||||
if (opts.list_dependencies)
|
||||
{
|
||||
set<string> deps1, deps2;
|
||||
get_dependencies(*c1, opts.added_bins_dirs1, deps1);
|
||||
get_dependencies(*c2, opts.added_bins_dirs2, deps2);
|
||||
display_dependencies(argv[0], c1, c2, deps1, deps2);
|
||||
return abigail::tools_utils::ABIDIFF_OK;
|
||||
}
|
||||
const auto c1_version = c1->get_format_major_version_number();
|
||||
const auto c2_version = c2->get_format_major_version_number();
|
||||
if (c1_version != c2_version)
|
||||
{
|
||||
emit_incompatible_format_version_error_message(opts.file1,
|
||||
c1_version,
|
||||
opts.file2,
|
||||
c2_version,
|
||||
argv[0]);
|
||||
return abigail::tools_utils::ABIDIFF_ERROR;
|
||||
}
|
||||
|
||||
set_corpus_keep_drop_regex_patterns(opts, c1);
|
||||
set_corpus_keep_drop_regex_patterns(opts, c2);
|
||||
|
||||
tools_utils::timer t;
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.start();
|
||||
std::cerr << "Compute diff ...\n";
|
||||
}
|
||||
|
||||
corpus_diff_sptr diff = compute_diff(c1, c2, ctxt);
|
||||
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.stop();
|
||||
std::cerr << "diff computed!:" << t << "\n";
|
||||
}
|
||||
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.start();
|
||||
std::cerr << "Computing net changes ...\n";
|
||||
}
|
||||
|
||||
if (diff->has_net_changes())
|
||||
{
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.stop();
|
||||
std::cerr << "net changes computed!: "<< t << "\n";
|
||||
}
|
||||
status = abigail::tools_utils::ABIDIFF_ABI_CHANGE;
|
||||
}
|
||||
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.start();
|
||||
std::cerr << "Computing incompatible changes ...\n";
|
||||
}
|
||||
|
||||
if (diff->has_incompatible_changes())
|
||||
{
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.stop();
|
||||
std::cerr << "incompatible changes computed!: "<< t << "\n";
|
||||
}
|
||||
status |= abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE;
|
||||
}
|
||||
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.start();
|
||||
std::cerr << "Computing changes ...\n";
|
||||
}
|
||||
|
||||
if (diff->has_changes())
|
||||
{
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.stop();
|
||||
std::cerr << "changes computed!: "<< t << "\n";
|
||||
}
|
||||
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.start();
|
||||
std::cerr << "Computing report ...\n";
|
||||
}
|
||||
|
||||
diff->report(cout);
|
||||
|
||||
if (opts.do_log)
|
||||
{
|
||||
t.stop();
|
||||
std::cerr << "Report computed!:" << t << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
status = abigail::tools_utils::ABIDIFF_ERROR;
|
||||
|
||||
+158
-11
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include "abg-config.h"
|
||||
#include "abg-tools-utils.h"
|
||||
#include "abg-corpus.h"
|
||||
@@ -29,6 +30,9 @@
|
||||
#ifdef WITH_CTF
|
||||
#include "abg-ctf-reader.h"
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
#include "abg-btf-reader.h"
|
||||
#endif
|
||||
#include "abg-writer.h"
|
||||
#include "abg-reader.h"
|
||||
#include "abg-comparison.h"
|
||||
@@ -40,7 +44,9 @@ using std::cout;
|
||||
using std::ostream;
|
||||
using std::ofstream;
|
||||
using std::vector;
|
||||
using std::set;
|
||||
using std::shared_ptr;
|
||||
using std::static_pointer_cast;
|
||||
using abg_compat::optional;
|
||||
using abigail::tools_utils::emit_prefix;
|
||||
using abigail::tools_utils::temp_file;
|
||||
@@ -49,6 +55,9 @@ using abigail::tools_utils::check_file;
|
||||
using abigail::tools_utils::build_corpus_group_from_kernel_dist_under;
|
||||
using abigail::tools_utils::timer;
|
||||
using abigail::tools_utils::create_best_elf_based_reader;
|
||||
using abigail::tools_utils::stick_corpus_and_dependencies_into_corpus_group;
|
||||
using abigail::tools_utils::stick_corpus_and_binaries_into_corpus_group;
|
||||
using abigail::tools_utils::add_dependencies_into_corpus_group;
|
||||
using abigail::ir::environment_sptr;
|
||||
using abigail::ir::environment;
|
||||
using abigail::corpus;
|
||||
@@ -68,6 +77,7 @@ using abigail::xml_writer::create_write_context;
|
||||
using abigail::xml_writer::type_id_style_kind;
|
||||
using abigail::xml_writer::write_context_sptr;
|
||||
using abigail::xml_writer::write_corpus;
|
||||
using abigail::xml_writer::write_corpus_group;
|
||||
using abigail::abixml::read_corpus_from_abixml_file;
|
||||
|
||||
using namespace abigail;
|
||||
@@ -81,6 +91,8 @@ struct options
|
||||
vector<char**> prepared_di_root_paths;
|
||||
vector<string> headers_dirs;
|
||||
vector<string> header_files;
|
||||
vector<string> added_bins_dirs;
|
||||
vector<string> added_bins;
|
||||
string vmlinux;
|
||||
vector<string> suppression_paths;
|
||||
vector<string> kabi_whitelist_paths;
|
||||
@@ -101,8 +113,13 @@ struct options
|
||||
bool corpus_group_for_linux;
|
||||
bool show_stats;
|
||||
bool noout;
|
||||
bool follow_dependencies;
|
||||
bool list_dependencies;
|
||||
#ifdef WITH_CTF
|
||||
bool use_ctf;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
bool use_btf;
|
||||
#endif
|
||||
bool show_locs;
|
||||
bool abidiff;
|
||||
@@ -142,8 +159,13 @@ struct options
|
||||
corpus_group_for_linux(false),
|
||||
show_stats(),
|
||||
noout(),
|
||||
follow_dependencies(),
|
||||
list_dependencies(),
|
||||
#ifdef WITH_CTF
|
||||
use_ctf(false),
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
use_btf(false),
|
||||
#endif
|
||||
show_locs(true),
|
||||
abidiff(),
|
||||
@@ -220,6 +242,12 @@ display_usage(const string& prog_name, ostream& out)
|
||||
<< " --vmlinux <path> the path to the vmlinux binary to consider to emit "
|
||||
"the ABI of the union of vmlinux and its modules\n"
|
||||
<< " --abidiff compare the loaded ABI against itself\n"
|
||||
<< " --add-binaries <bin1,bin2,...> build a corpus group with "
|
||||
"the added inaries\n"
|
||||
<< " --follow-dependencies build a corpus group with the dependencies\n"
|
||||
<< " --list-dependencies list the dependencies of a given binary\n"
|
||||
<< " --added-binaries-dir|--abd <dir-of-deps> where to look for dependencies "
|
||||
"or added binaries\n"
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
<< " --debug-abidiff debug the process of comparing the loaded ABI against itself\n"
|
||||
#endif
|
||||
@@ -234,6 +262,9 @@ display_usage(const string& prog_name, ostream& out)
|
||||
"speed-up the analysis of the binary\n"
|
||||
<< " --no-assume-odr-for-cplusplus do not assume the ODR to speed-up the "
|
||||
"analysis of the binary\n"
|
||||
#ifdef WITH_BTF
|
||||
<< " --btf use BTF instead of DWARF in ELF files\n"
|
||||
#endif
|
||||
<< " --annotate annotate the ABI artifacts emitted in the output\n"
|
||||
<< " --stats show statistics about various internal stuff\n"
|
||||
<< " --verbose show verbose messages about internal stuff\n";
|
||||
@@ -282,6 +313,15 @@ parse_command_line(int argc, char* argv[], options& opts)
|
||||
opts.headers_dirs.push_back(argv[j]);
|
||||
++i;
|
||||
}
|
||||
else if (!strcmp(argv[i], "--added-binaries-dir")
|
||||
|| !strcmp(argv[i], "--abd"))
|
||||
{
|
||||
int j = i + 1;
|
||||
if (j >= argc)
|
||||
return false;
|
||||
opts.added_bins_dirs.push_back(argv[j]);
|
||||
++i;
|
||||
}
|
||||
else if (!strcmp(argv[i], "--header-file")
|
||||
|| !strcmp(argv[i], "--hf"))
|
||||
{
|
||||
@@ -332,9 +372,35 @@ parse_command_line(int argc, char* argv[], options& opts)
|
||||
}
|
||||
else if (!strcmp(argv[i], "--noout"))
|
||||
opts.noout = true;
|
||||
else if (!strcmp(argv[i], "--follow-dependencies"))
|
||||
opts.follow_dependencies = true;
|
||||
else if (!strcmp(argv[i], "--list-dependencies"))
|
||||
opts.list_dependencies = true;
|
||||
else if (!strncmp(argv[i], "--add-binaries=",
|
||||
strlen("--add-binaries=")))
|
||||
tools_utils::get_comma_separated_args_of_option(argv[i],
|
||||
"--add-binaries=",
|
||||
opts.added_bins);
|
||||
else if (!strcmp(argv[i], "--add-binaries"))
|
||||
{
|
||||
int j = i + 1;
|
||||
if (j >= argc)
|
||||
return false;
|
||||
|
||||
string s = argv[j];
|
||||
if (s.find(','))
|
||||
tools_utils::split_string(s, ",", opts.added_bins);
|
||||
else
|
||||
opts.added_bins.push_back(s);
|
||||
++i;
|
||||
}
|
||||
#ifdef WITH_CTF
|
||||
else if (!strcmp(argv[i], "--ctf"))
|
||||
opts.use_ctf = true;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
else if (!strcmp(argv[i], "--btf"))
|
||||
opts.use_btf = true;
|
||||
#endif
|
||||
else if (!strcmp(argv[i], "--no-architecture"))
|
||||
opts.write_architecture = false;
|
||||
@@ -582,12 +648,17 @@ load_corpus_and_write_abixml(char* argv[],
|
||||
#endif
|
||||
|
||||
corpus_sptr corp;
|
||||
corpus_group_sptr corp_group;
|
||||
fe_iface::status s = fe_iface::STATUS_UNKNOWN;
|
||||
corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
|
||||
#ifdef WITH_CTF
|
||||
if (opts.use_ctf)
|
||||
requested_fe_kind = corpus::CTF_ORIGIN;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
if (opts.use_btf)
|
||||
requested_fe_kind = corpus::BTF_ORIGIN;
|
||||
#endif
|
||||
|
||||
// First of all, create a reader to read the ABI from the file
|
||||
// specfied in opts ...
|
||||
@@ -642,11 +713,6 @@ load_corpus_and_write_abixml(char* argv[],
|
||||
emit_prefix(argv[0], cerr)
|
||||
<< "read corpus from elf file in: " << t << "\n";
|
||||
|
||||
// Clear some resources to gain back some space.
|
||||
t.start();
|
||||
reader.reset();
|
||||
t.stop();
|
||||
|
||||
if (opts.do_log)
|
||||
emit_prefix(argv[0], cerr)
|
||||
<< "reset reader ELF in: " << t << "\n";
|
||||
@@ -689,10 +755,71 @@ load_corpus_and_write_abixml(char* argv[],
|
||||
emit_prefix(argv[0], cerr)
|
||||
<< "Could not read ELF symbol information from "
|
||||
<< opts.in_file_path << "\n";
|
||||
else if (s & fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
|
||||
{
|
||||
emit_prefix(argv[0], cerr)
|
||||
<< "Could not read alternate debug info file";
|
||||
if (!reader->alternate_dwarf_debug_info_path().empty())
|
||||
cerr << " '" << reader->alternate_dwarf_debug_info_path() << "'";
|
||||
cerr << " for '"
|
||||
<< opts.in_file_path << "'.\n";
|
||||
emit_prefix(argv[0], cerr)
|
||||
<< "You might have forgotten to install some "
|
||||
"additional needed debug info\n";
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (opts.list_dependencies)
|
||||
{
|
||||
// Show the dependencies of the corpus and display them.
|
||||
set<string> dependencies;
|
||||
if (tools_utils::get_dependencies(*corp, opts.added_bins_dirs,
|
||||
dependencies))
|
||||
{
|
||||
cout << "Dependencies of '" << corp->get_path()
|
||||
<< "':\n\t";
|
||||
int n = 0;
|
||||
for (const auto& dep : dependencies)
|
||||
{
|
||||
if (n)
|
||||
cout << ", ";
|
||||
cout << dep;
|
||||
++n;
|
||||
}
|
||||
cout << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (!opts.added_bins.empty())
|
||||
corp_group =
|
||||
stick_corpus_and_binaries_into_corpus_group(reader, corp,
|
||||
opts.added_bins,
|
||||
opts.added_bins_dirs);
|
||||
|
||||
if (opts.follow_dependencies)
|
||||
{
|
||||
// load the dependencies of the corpus and put them all into a
|
||||
// corpus group.
|
||||
|
||||
// If a corpus_group already exists, use that one ...
|
||||
if (!corp_group->is_empty())
|
||||
add_dependencies_into_corpus_group(reader, *corp,
|
||||
opts.added_bins_dirs,
|
||||
*corp_group);
|
||||
else
|
||||
// .. otherwise, create a new corpus group.
|
||||
corp_group =
|
||||
stick_corpus_and_dependencies_into_corpus_group(reader, corp,
|
||||
opts.added_bins_dirs);
|
||||
}
|
||||
|
||||
// Clear some resources to gain back some space.
|
||||
t.start();
|
||||
reader.reset();
|
||||
t.stop();
|
||||
|
||||
// Now create a write context and write out an ABI XML description
|
||||
// of the read corpus.
|
||||
t.start();
|
||||
@@ -712,7 +839,10 @@ load_corpus_and_write_abixml(char* argv[],
|
||||
// against the ABI of the input ELF file.
|
||||
temp_file_sptr tmp_file = temp_file::create();
|
||||
set_ostream(*write_ctxt, tmp_file->get_stream());
|
||||
write_corpus(*write_ctxt, corp, 0);
|
||||
if (corp_group)
|
||||
write_corpus_group(*write_ctxt, corp_group, 0);
|
||||
else
|
||||
write_corpus(*write_ctxt, corp, 0);
|
||||
tmp_file->get_stream().flush();
|
||||
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
@@ -731,7 +861,14 @@ load_corpus_and_write_abixml(char* argv[],
|
||||
#endif
|
||||
t.start();
|
||||
fe_iface::status sts;
|
||||
corpus_sptr corp2 = rdr->read_corpus(sts);
|
||||
corpus_sptr corp2;
|
||||
corpus_group_sptr corp_group2;
|
||||
|
||||
if (corp_group)
|
||||
corp_group2 = abixml::read_corpus_group_from_input(*rdr);
|
||||
else
|
||||
corp2 = rdr->read_corpus(sts);
|
||||
|
||||
t.stop();
|
||||
if (opts.do_log)
|
||||
emit_prefix(argv[0], cerr)
|
||||
@@ -749,7 +886,11 @@ load_corpus_and_write_abixml(char* argv[],
|
||||
set_diff_context(ctxt);
|
||||
ctxt->show_locs(opts.show_locs);
|
||||
t.start();
|
||||
corpus_diff_sptr diff = compute_diff(corp, corp2, ctxt);
|
||||
corpus_diff_sptr diff =
|
||||
corp_group2
|
||||
? compute_diff(corp_group, corp_group2, ctxt)
|
||||
: compute_diff(corp, corp2, ctxt);
|
||||
|
||||
t.stop();
|
||||
if (opts.do_log)
|
||||
emit_prefix(argv[0], cerr)
|
||||
@@ -790,7 +931,10 @@ load_corpus_and_write_abixml(char* argv[],
|
||||
}
|
||||
set_ostream(*write_ctxt, of);
|
||||
t.start();
|
||||
write_corpus(*write_ctxt, corp, 0);
|
||||
if (corp_group)
|
||||
write_corpus_group(*write_ctxt, corp_group, 0);
|
||||
else
|
||||
write_corpus(*write_ctxt, corp, 0);
|
||||
t.stop();
|
||||
if (opts.do_log)
|
||||
emit_prefix(argv[0], cerr)
|
||||
@@ -801,7 +945,10 @@ load_corpus_and_write_abixml(char* argv[],
|
||||
else
|
||||
{
|
||||
t.start();
|
||||
exit_code = !write_corpus(*write_ctxt, corp, 0);
|
||||
exit_code =
|
||||
corp_group
|
||||
? !write_corpus_group(*write_ctxt, corp_group, 0)
|
||||
: !write_corpus(*write_ctxt, corp, 0);
|
||||
t.stop();
|
||||
if (opts.do_log)
|
||||
emit_prefix(argv[0], cerr)
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
|
||||
+349
-161
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2015-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2015-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Sinny Kumari
|
||||
|
||||
@@ -93,6 +93,9 @@
|
||||
#ifdef WITH_CTF
|
||||
#include "abg-ctf-reader.h"
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
#include "abg-btf-reader.h"
|
||||
#endif
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
@@ -212,6 +215,9 @@ public:
|
||||
#ifdef WITH_CTF
|
||||
bool use_ctf;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
bool use_btf;
|
||||
#endif
|
||||
|
||||
vector<string> kabi_whitelist_packages;
|
||||
vector<string> suppression_paths;
|
||||
@@ -256,6 +262,10 @@ public:
|
||||
#ifdef WITH_CTF
|
||||
,
|
||||
use_ctf()
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
,
|
||||
use_btf()
|
||||
#endif
|
||||
{
|
||||
// set num_workers to the default number of threads of the
|
||||
@@ -271,6 +281,9 @@ get_interesting_files_under_dir(const string dir,
|
||||
options& opts,
|
||||
vector<string>& interesting_files);
|
||||
|
||||
static string
|
||||
get_pretty_printed_list_of_packages(const vector<string>& packages);
|
||||
|
||||
/// Abstract ELF files from the packages which ABIs ought to be
|
||||
/// compared
|
||||
class elf_file
|
||||
@@ -716,12 +729,16 @@ public:
|
||||
if (system(cmd.c_str()))
|
||||
{
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr) << " FAILED\n";
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Erasing temporary extraction directory"
|
||||
<< " FAILED\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr) << " DONE\n";
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Erasing temporary extraction directory"
|
||||
<< " DONE\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -905,6 +922,9 @@ display_usage(const string& prog_name, ostream& out)
|
||||
"binaries inside the input package against their ABIXML representation\n"
|
||||
#ifdef WITH_CTF
|
||||
<< " --ctf use CTF instead of DWARF in ELF files\n"
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
<< " --btf use BTF instead of DWARF in ELF files\n"
|
||||
#endif
|
||||
<< " --help|-h display this help message\n"
|
||||
<< " --version|-v display program version information"
|
||||
@@ -934,7 +954,7 @@ extract_rpm(const string& package_path,
|
||||
<< package_path
|
||||
<< " to "
|
||||
<< extracted_package_dir_path
|
||||
<< " ...";
|
||||
<< " ...\n";
|
||||
|
||||
string cmd = "test -d " + extracted_package_dir_path
|
||||
+ " || mkdir -p " + extracted_package_dir_path + " ; cd " +
|
||||
@@ -944,12 +964,22 @@ extract_rpm(const string& package_path,
|
||||
if (system(cmd.c_str()))
|
||||
{
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr) << " FAILED\n";
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Extracting package "
|
||||
<< package_path
|
||||
<< " to "
|
||||
<< extracted_package_dir_path
|
||||
<< " FAILED\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr) << " DONE\n";
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Extracting package "
|
||||
<< package_path
|
||||
<< " to "
|
||||
<< extracted_package_dir_path
|
||||
<< " DONE\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -987,13 +1017,22 @@ extract_deb(const string& package_path,
|
||||
if (system(cmd.c_str()))
|
||||
{
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr) << " FAILED\n";
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Extracting package "
|
||||
<< package_path
|
||||
<< " to "
|
||||
<< extracted_package_dir_path
|
||||
<< " FAILED\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr) << " DONE\n";
|
||||
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Extracting package "
|
||||
<< package_path
|
||||
<< " to "
|
||||
<< extracted_package_dir_path
|
||||
<< " DONE\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1040,12 +1079,22 @@ extract_tar(const string& package_path,
|
||||
if (system(cmd.c_str()))
|
||||
{
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr) << " FAILED\n";
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Extracting tar archive "
|
||||
<< package_path
|
||||
<< " to "
|
||||
<< extracted_package_dir_path
|
||||
<< " FAILED\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr) << " DONE\n";
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Extracting tar archive "
|
||||
<< package_path
|
||||
<< " to "
|
||||
<< extracted_package_dir_path
|
||||
<< " DONE\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1084,12 +1133,18 @@ erase_created_temporary_directories_parent(const options &opts)
|
||||
if (system(cmd.c_str()))
|
||||
{
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr) << "FAILED\n";
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Erasing temporary extraction parent directory "
|
||||
<< package::extracted_packages_parent_dir()
|
||||
<< "FAILED\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr) << "DONE\n";
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Erasing temporary extraction parent directory "
|
||||
<< package::extracted_packages_parent_dir()
|
||||
<< "DONE\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1250,6 +1305,68 @@ set_generic_options(abigail::elf_based_reader& rdr, const options& opts)
|
||||
opts.assume_odr_for_cplusplus;
|
||||
}
|
||||
|
||||
/// Emit an error message on standard error about alternate debug info
|
||||
/// not being found.
|
||||
///
|
||||
/// @param reader the ELF based reader being used.
|
||||
///
|
||||
/// @param elf_file the ELF file being looked at.
|
||||
///
|
||||
/// @param opts the options passed to the tool.
|
||||
///
|
||||
/// @param is_old_package if this is true, then we are looking at the
|
||||
/// first (the old) package of the comparison. Otherwise, we are
|
||||
/// looking at the second (the newest) package of the comparison.
|
||||
static void
|
||||
emit_alt_debug_info_not_found_error(abigail::elf_based_reader& reader,
|
||||
const elf_file& elf_file,
|
||||
const options& opts,
|
||||
ostream& out,
|
||||
bool is_old_package)
|
||||
{
|
||||
ABG_ASSERT(is_old_package
|
||||
? !opts.debug_packages1.empty()
|
||||
: !opts.debug_packages2.empty());
|
||||
|
||||
string filename;
|
||||
tools_utils::base_name(elf_file.path, filename);
|
||||
emit_prefix("abipkgdiff", out)
|
||||
<< "While reading elf file '"
|
||||
<< filename
|
||||
<< "', could not find alternate debug info in provided "
|
||||
"debug info package(s) "
|
||||
<< get_pretty_printed_list_of_packages(is_old_package
|
||||
? opts.debug_packages1
|
||||
: opts.debug_packages2)
|
||||
<< "\n";
|
||||
|
||||
string alt_di_path;
|
||||
#ifdef WITH_CTF
|
||||
if (opts.use_ctf)
|
||||
;
|
||||
else
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
if (opts.use_btf)
|
||||
;
|
||||
else
|
||||
#endif
|
||||
reader.refers_to_alt_debug_info(alt_di_path);
|
||||
if (!alt_di_path.empty())
|
||||
{
|
||||
emit_prefix("abipkgdiff", out)
|
||||
<< "The alternate debug info file being looked for is: "
|
||||
<< alt_di_path << "\n";
|
||||
}
|
||||
else
|
||||
emit_prefix("abipkgdiff", out) << "\n";
|
||||
|
||||
emit_prefix("abipkgdiff", out)
|
||||
<< "You must provide the additional "
|
||||
<< "debug info package that contains that alternate "
|
||||
<< "debug info file, using an additional --d1/--d2 switch\n";
|
||||
}
|
||||
|
||||
/// Compare the ABI two elf files, using their associated debug info.
|
||||
///
|
||||
/// The result of the comparison is emitted to standard output.
|
||||
@@ -1289,6 +1406,7 @@ compare(const elf_file& elf1,
|
||||
abigail::ir::environment& env,
|
||||
corpus_diff_sptr& diff,
|
||||
diff_context_sptr& ctxt,
|
||||
ostream& out,
|
||||
abigail::fe_iface::status* detailed_error_status = 0)
|
||||
{
|
||||
char *di_dir1 = (char*) debug_dir1.c_str(),
|
||||
@@ -1353,6 +1471,10 @@ compare(const elf_file& elf1,
|
||||
#ifdef WITH_CTF
|
||||
if (opts.use_ctf)
|
||||
requested_fe_kind = corpus::CTF_ORIGIN;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
if (opts.use_btf)
|
||||
requested_fe_kind = corpus::BTF_ORIGIN;
|
||||
#endif
|
||||
abigail::elf_based_reader_sptr reader =
|
||||
create_best_elf_based_reader(elf1.path,
|
||||
@@ -1381,6 +1503,15 @@ compare(const elf_file& elf1,
|
||||
bail_out = true;
|
||||
}
|
||||
|
||||
if (c1_status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
|
||||
{
|
||||
emit_alt_debug_info_not_found_error(*reader, elf1, opts, out,
|
||||
/*is_old_package=*/true);
|
||||
if (detailed_error_status)
|
||||
*detailed_error_status = c1_status;
|
||||
bail_out = true;
|
||||
}
|
||||
|
||||
if (opts.fail_if_no_debug_info)
|
||||
{
|
||||
bool debug_info_error = false;
|
||||
@@ -1401,31 +1532,6 @@ compare(const elf_file& elf1,
|
||||
debug_info_error = true;
|
||||
}
|
||||
|
||||
if (c1_status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
|
||||
{
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "while reading file" << elf1.path << "\n";
|
||||
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Could not find alternate debug info file";
|
||||
string alt_di_path;
|
||||
#ifdef WITH_CTF
|
||||
if (opts.use_ctf)
|
||||
;
|
||||
else
|
||||
#endif
|
||||
reader->refers_to_alt_debug_info(alt_di_path);
|
||||
if (!alt_di_path.empty())
|
||||
cerr << ": " << alt_di_path << "\n";
|
||||
else
|
||||
cerr << "\n";
|
||||
|
||||
if (detailed_error_status)
|
||||
*detailed_error_status = c1_status;
|
||||
debug_info_error = true;
|
||||
}
|
||||
|
||||
if (debug_info_error)
|
||||
bail_out = true;
|
||||
}
|
||||
@@ -1449,10 +1555,16 @@ compare(const elf_file& elf1,
|
||||
corpus_sptr corpus2;
|
||||
{
|
||||
corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
|
||||
|
||||
#ifdef WITH_CTF
|
||||
if (opts.use_ctf)
|
||||
requested_fe_kind = corpus::CTF_ORIGIN;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
if (opts.use_btf)
|
||||
requested_fe_kind = corpus::BTF_ORIGIN;
|
||||
#endif
|
||||
|
||||
abigail::elf_based_reader_sptr reader =
|
||||
create_best_elf_based_reader(elf2.path,
|
||||
di_dirs2,
|
||||
@@ -1480,6 +1592,15 @@ compare(const elf_file& elf1,
|
||||
bail_out = true;
|
||||
}
|
||||
|
||||
if (c2_status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
|
||||
{
|
||||
emit_alt_debug_info_not_found_error(*reader, elf2, opts, out,
|
||||
/*is_old_package=*/false);
|
||||
if (detailed_error_status)
|
||||
*detailed_error_status = c2_status;
|
||||
bail_out = true;
|
||||
}
|
||||
|
||||
if (opts.fail_if_no_debug_info)
|
||||
{
|
||||
bool debug_info_error = false;
|
||||
@@ -1500,31 +1621,6 @@ compare(const elf_file& elf1,
|
||||
debug_info_error = true;
|
||||
}
|
||||
|
||||
if (c2_status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
|
||||
{
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "while reading file" << elf2.path << "\n";
|
||||
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Could not find alternate debug info file";
|
||||
string alt_di_path;
|
||||
#ifdef WITH_CTF
|
||||
if (opts.use_ctf)
|
||||
;
|
||||
else
|
||||
#endif
|
||||
reader->refers_to_alt_debug_info(alt_di_path);
|
||||
if (!alt_di_path.empty())
|
||||
cerr << ": " << alt_di_path << "\n";
|
||||
else
|
||||
cerr << "\n";
|
||||
|
||||
if (detailed_error_status)
|
||||
*detailed_error_status = c2_status;
|
||||
debug_info_error = true;
|
||||
}
|
||||
|
||||
if (debug_info_error)
|
||||
bail_out = true;
|
||||
}
|
||||
@@ -1589,6 +1685,7 @@ compare_to_self(const elf_file& elf,
|
||||
abigail::ir::environment& env,
|
||||
corpus_diff_sptr& diff,
|
||||
diff_context_sptr& ctxt,
|
||||
ostream& out,
|
||||
abigail::fe_iface::status* detailed_error_status = 0)
|
||||
{
|
||||
char *di_dir = (char*) debug_dir.c_str();
|
||||
@@ -1617,6 +1714,10 @@ compare_to_self(const elf_file& elf,
|
||||
#ifdef WITH_CTF
|
||||
if (opts.use_ctf)
|
||||
requested_fe_kind = corpus::CTF_ORIGIN;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
if (opts.use_btf)
|
||||
requested_fe_kind = corpus::BTF_ORIGIN;
|
||||
#endif
|
||||
abigail::elf_based_reader_sptr reader =
|
||||
create_best_elf_based_reader(elf.path,
|
||||
@@ -1633,13 +1734,21 @@ compare_to_self(const elf_file& elf,
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Could not read file '"
|
||||
<< elf.path
|
||||
<< "' propertly\n";
|
||||
<< "' properly\n";
|
||||
|
||||
if (detailed_error_status)
|
||||
*detailed_error_status = c_status;
|
||||
|
||||
return abigail::tools_utils::ABIDIFF_ERROR;
|
||||
}
|
||||
else if (c_status & abigail::fe_iface::STATUS_ALT_DEBUG_INFO_NOT_FOUND)
|
||||
{
|
||||
emit_alt_debug_info_not_found_error(*reader, elf, opts, out,
|
||||
/*is_old_package=*/true);
|
||||
if (detailed_error_status)
|
||||
*detailed_error_status = c_status;
|
||||
return abigail::tools_utils::ABIDIFF_ERROR;
|
||||
}
|
||||
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
@@ -1746,7 +1855,10 @@ compare_to_self(const elf_file& elf,
|
||||
diff = compute_diff(corp, reread_corp, ctxt);
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdfiff", cerr)
|
||||
<< "... Comparing the ABIs: DONE\n";
|
||||
<< "Comparing the ABIs: of \n"
|
||||
<< " '" << corp->get_path() << "' against \n"
|
||||
<< " '" << abi_file_path << "':"
|
||||
<< "DONE\n";
|
||||
|
||||
abidiff_status s = abigail::tools_utils::ABIDIFF_OK;
|
||||
if (diff->has_changes())
|
||||
@@ -1943,8 +2055,8 @@ maybe_handle_kabi_whitelist_pkg(const package& pkg, options &opts)
|
||||
if (pkg.type() != abigail::tools_utils::FILE_TYPE_RPM)
|
||||
return false;
|
||||
|
||||
string pkg_name = pkg.base_name();
|
||||
bool is_linux_kernel_package = file_is_kernel_package(pkg_name, pkg.type());
|
||||
bool is_linux_kernel_package = file_is_kernel_package(pkg.path(),
|
||||
pkg.type());
|
||||
|
||||
if (!is_linux_kernel_package)
|
||||
return false;
|
||||
@@ -1957,7 +2069,7 @@ maybe_handle_kabi_whitelist_pkg(const package& pkg, options &opts)
|
||||
return false;
|
||||
|
||||
string rpm_arch;
|
||||
if (!get_rpm_arch(pkg_name, rpm_arch))
|
||||
if (!get_rpm_arch(pkg.base_name(), rpm_arch))
|
||||
return false;
|
||||
|
||||
string kabi_wl_path = kabi_wl_pkg->extracted_dir_path();
|
||||
@@ -2068,6 +2180,60 @@ public:
|
||||
status(abigail::tools_utils::ABIDIFF_OK)
|
||||
{}
|
||||
|
||||
void
|
||||
maybe_emit_pretty_error_message_to_output(const corpus_diff_sptr& diff,
|
||||
abigail::fe_iface::status detailed_status)
|
||||
{
|
||||
// If there is an ABI change, tell the user about it.
|
||||
if ((status & abigail::tools_utils::ABIDIFF_ABI_CHANGE)
|
||||
||( diff && diff->has_net_changes()))
|
||||
{
|
||||
diff->report(out, /*prefix=*/" ");
|
||||
string name = args->elf1.name;
|
||||
|
||||
pretty_output +=
|
||||
string("================ changes of '") + name + "'===============\n"
|
||||
+ out.str()
|
||||
+ "================ end of changes of '"
|
||||
+ name + "'===============\n\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (args->opts.show_identical_binaries)
|
||||
{
|
||||
out << "No ABI change detected\n";
|
||||
pretty_output += out.str();
|
||||
}
|
||||
}
|
||||
|
||||
// If an error happened while comparing the two binaries, tell the
|
||||
// user about it.
|
||||
if (status & abigail::tools_utils::ABIDIFF_ERROR)
|
||||
{
|
||||
string diagnostic =
|
||||
abigail::status_to_diagnostic_string(detailed_status);
|
||||
if (diagnostic.empty())
|
||||
diagnostic =
|
||||
"Unknown error. Please run the tool again with --verbose\n";
|
||||
|
||||
string name = args->elf1.name;
|
||||
std::stringstream o;
|
||||
emit_prefix("abipkgdiff", o)
|
||||
<< "==== Error happened during processing of '"
|
||||
<< name
|
||||
<< "' ====\n";
|
||||
emit_prefix("abipkgdiff", o)
|
||||
<< diagnostic
|
||||
<< ":\n"
|
||||
<< out.str();
|
||||
emit_prefix("abipkgdiff", o)
|
||||
<< "==== End of error for '"
|
||||
<< name
|
||||
<< "' ====\n\n";
|
||||
pretty_output += o.str();
|
||||
}
|
||||
}
|
||||
|
||||
/// The job performed by the task.
|
||||
///
|
||||
/// This compares two ELF files, gets the resulting test report and
|
||||
@@ -2088,44 +2254,9 @@ public:
|
||||
|
||||
status |= compare(args->elf1, args->debug_dir1, args->private_types_suppr1,
|
||||
args->elf2, args->debug_dir2, args->private_types_suppr2,
|
||||
args->opts, env, diff, ctxt, &detailed_status);
|
||||
args->opts, env, diff, ctxt, out, &detailed_status);
|
||||
|
||||
// If there is an ABI change, tell the user about it.
|
||||
if ((status & abigail::tools_utils::ABIDIFF_ABI_CHANGE)
|
||||
||( diff && diff->has_net_changes()))
|
||||
{
|
||||
diff->report(out, /*prefix=*/" ");
|
||||
string name = args->elf1.name;
|
||||
|
||||
pretty_output +=
|
||||
string("================ changes of '") + name + "'===============\n"
|
||||
+ out.str()
|
||||
+ "================ end of changes of '"
|
||||
+ name + "'===============\n\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (args->opts.show_identical_binaries)
|
||||
out << "No ABI change detected\n";
|
||||
}
|
||||
|
||||
// If an error happened while comparing the two binaries, tell the
|
||||
// user about it.
|
||||
if (status & abigail::tools_utils::ABIDIFF_ERROR)
|
||||
{
|
||||
string diagnostic =
|
||||
abigail::status_to_diagnostic_string(detailed_status);
|
||||
if (diagnostic.empty())
|
||||
diagnostic =
|
||||
"Unknown error. Please run the tool again with --verbose\n";
|
||||
|
||||
string name = args->elf1.name;
|
||||
pretty_output +=
|
||||
"==== Error happened during processing of '" + name + "' ====\n";
|
||||
pretty_output += diagnostic;
|
||||
pretty_output +=
|
||||
"==== End of error for '" + name + "' ====\n";
|
||||
}
|
||||
maybe_emit_pretty_error_message_to_output(diff, detailed_status);
|
||||
}
|
||||
}; // end class compare_task
|
||||
|
||||
@@ -2160,44 +2291,14 @@ public:
|
||||
abigail::fe_iface::STATUS_UNKNOWN;
|
||||
|
||||
status |= compare_to_self(args->elf1, args->debug_dir1,
|
||||
args->opts, env, diff, ctxt,
|
||||
args->opts, env, diff, ctxt, out,
|
||||
&detailed_status);
|
||||
|
||||
string name = args->elf1.name;
|
||||
if (status == abigail::tools_utils::ABIDIFF_OK)
|
||||
pretty_output += "==== SELF CHECK SUCCEEDED for '"+ name + "' ====\n";
|
||||
else if ((status & abigail::tools_utils::ABIDIFF_ABI_CHANGE)
|
||||
||( diff && diff->has_net_changes()))
|
||||
{
|
||||
// There is an ABI change, tell the user about it.
|
||||
diff->report(out, /*indent=*/" ");
|
||||
|
||||
pretty_output +=
|
||||
string("======== comparing'") + name +
|
||||
"' to itself wrongly yielded result: ===========\n"
|
||||
+ out.str()
|
||||
+ "===SELF CHECK FAILED for '"+ name + "'\n";
|
||||
}
|
||||
|
||||
// If an error happened while comparing the two binaries, tell the
|
||||
// user about it.
|
||||
if (status & abigail::tools_utils::ABIDIFF_ERROR)
|
||||
{
|
||||
string diagnostic =
|
||||
abigail::status_to_diagnostic_string(detailed_status);
|
||||
|
||||
if (diagnostic.empty())
|
||||
diagnostic =
|
||||
"Unknown error. Please run the tool again with --verbose\n";
|
||||
|
||||
string name = args->elf1.name;
|
||||
pretty_output +=
|
||||
"==== Error happened during self check of '" + name + "' ====\n";
|
||||
pretty_output += diagnostic;
|
||||
pretty_output +=
|
||||
"==== SELF CHECK FAILED for '" + name + "' ====\n";
|
||||
|
||||
}
|
||||
else
|
||||
maybe_emit_pretty_error_message_to_output(diff, detailed_status);
|
||||
}
|
||||
}; // end class self_compare
|
||||
|
||||
@@ -2222,14 +2323,20 @@ typedef shared_ptr<self_compare_task> self_compare_task_sptr;
|
||||
/// function only looks for a file name which name is the same as the
|
||||
/// value of this parameter.
|
||||
///
|
||||
/// @param parent_dir_name the name of the directory that the file
|
||||
/// name denoted by @p entry should belong to. If it doesn't (because
|
||||
/// it's a symlink that resolves to a file outside of that directory)
|
||||
/// then the vector of paths of is not updated.
|
||||
///
|
||||
/// @param paths out parameter. This is the set of meaningful paths
|
||||
/// of the current directory tree being analyzed. These paths are
|
||||
/// those that are going to be involved in ABI comparison.
|
||||
static void
|
||||
maybe_update_package_content(const FTSENT *entry,
|
||||
options &opts,
|
||||
const string& file_name_to_look_for,
|
||||
unordered_set<string>& paths)
|
||||
maybe_update_package_content(const FTSENT* entry,
|
||||
options& opts,
|
||||
const string& file_name_to_look_for,
|
||||
const string& parent_dir_name,
|
||||
unordered_set<string>& paths)
|
||||
{
|
||||
if (entry == NULL
|
||||
|| (entry->fts_info != FTS_F && entry->fts_info != FTS_SL)
|
||||
@@ -2239,6 +2346,15 @@ maybe_update_package_content(const FTSENT *entry,
|
||||
|
||||
string path = entry->fts_path;
|
||||
maybe_get_symlink_target_file_path(path, path);
|
||||
string parent_dir = parent_dir_name;
|
||||
maybe_get_symlink_target_file_path(parent_dir, parent_dir);
|
||||
|
||||
if (!parent_dir_name.empty())
|
||||
{
|
||||
string s;
|
||||
if (!string_suffix(path, parent_dir, s))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file_name_to_look_for.empty())
|
||||
{
|
||||
@@ -2290,7 +2406,7 @@ get_interesting_files_under_dir(const string dir,
|
||||
FTSENT *entry;
|
||||
unordered_set<string> files;
|
||||
while ((entry = fts_read(file_hierarchy)))
|
||||
maybe_update_package_content(entry, opts, file_name_to_look_for, files);
|
||||
maybe_update_package_content(entry, opts, file_name_to_look_for, dir, files);
|
||||
|
||||
for (unordered_set<string>::const_iterator i = files.begin();
|
||||
i != files.end();
|
||||
@@ -2304,6 +2420,33 @@ get_interesting_files_under_dir(const string dir,
|
||||
return is_ok;
|
||||
}
|
||||
|
||||
/// Return a string representing a list of packages that can be
|
||||
/// printed out to the user.
|
||||
///
|
||||
/// @param packages a vector of package names
|
||||
///
|
||||
/// @return a string representing the list of packages @p packages.
|
||||
static string
|
||||
get_pretty_printed_list_of_packages(const vector<string>& packages)
|
||||
{
|
||||
if (packages.empty())
|
||||
return string();
|
||||
|
||||
bool need_comma = false;
|
||||
std::stringstream o;
|
||||
for (auto p : packages)
|
||||
{
|
||||
string filename;
|
||||
tools_utils::base_name(p, filename);
|
||||
if (need_comma)
|
||||
o << ", ";
|
||||
else
|
||||
need_comma = true;
|
||||
o << "'" << filename << "'";
|
||||
}
|
||||
return o.str();
|
||||
}
|
||||
|
||||
/// Create maps of the content of a given package.
|
||||
///
|
||||
/// The maps contain relevant metadata about the content of the
|
||||
@@ -2333,8 +2476,7 @@ create_maps_of_package_content(package& package, options& opts)
|
||||
// if package is linux kernel package and its associated debug
|
||||
// info package looks like a kernel debuginfo package, then try to
|
||||
// go find the vmlinux file in that debug info file.
|
||||
string pkg_name = package.base_name();
|
||||
bool is_linux_kernel_package = file_is_kernel_package(pkg_name,
|
||||
bool is_linux_kernel_package = file_is_kernel_package(package.path(),
|
||||
package.type());
|
||||
if (is_linux_kernel_package)
|
||||
{
|
||||
@@ -2344,7 +2486,7 @@ create_maps_of_package_content(package& package, options& opts)
|
||||
is_ok = true;
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< " Analysis of " << package.path() << " DONE\n";
|
||||
<< " Analysis of linux package " << package.path() << " DONE\n";
|
||||
return is_ok;
|
||||
}
|
||||
|
||||
@@ -2369,6 +2511,12 @@ create_maps_of_package_content(package& package, options& opts)
|
||||
++file)
|
||||
{
|
||||
elf_file_sptr e (new elf_file(*file));
|
||||
string resolved_e_path;
|
||||
// The path 'e->path' might contain symlinks. Let's resolve
|
||||
// them so we can see if 'e->path' has already been seen before,
|
||||
// for instance.
|
||||
real_path(e->path, resolved_e_path);
|
||||
|
||||
if (opts.compare_dso_only)
|
||||
{
|
||||
if (e->type != abigail::elf::ELF_TYPE_DSO)
|
||||
@@ -2423,7 +2571,13 @@ create_maps_of_package_content(package& package, options& opts)
|
||||
// base name. So let's consider the full path of the binary
|
||||
// inside the extracted directory.
|
||||
string key = e->name;
|
||||
package.convert_path_to_unique_suffix(e->path, key);
|
||||
package.convert_path_to_unique_suffix(resolved_e_path, key);
|
||||
if (package.path_elf_file_sptr_map().find(key)
|
||||
!= package.path_elf_file_sptr_map().end())
|
||||
// 'key' has already been seen before. So we won't map it
|
||||
// twice.
|
||||
continue;
|
||||
|
||||
package.path_elf_file_sptr_map()[key] = e;
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
@@ -2453,11 +2607,18 @@ create_maps_of_package_content(package& package, options& opts)
|
||||
}
|
||||
}
|
||||
|
||||
if (package.convert_path_to_unique_suffix(e->path, key))
|
||||
if (package.convert_path_to_unique_suffix(resolved_e_path, key))
|
||||
{
|
||||
dir_name(key, key);
|
||||
key += string("/@soname:") + e->soname;
|
||||
}
|
||||
|
||||
if (package.path_elf_file_sptr_map().find(key)
|
||||
!= package.path_elf_file_sptr_map().end())
|
||||
// 'key' has already been seen before. So we won't do itl
|
||||
// twice.
|
||||
continue;
|
||||
|
||||
package.path_elf_file_sptr_map()[key] = e;
|
||||
if (opts.verbose)
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
@@ -3029,10 +3190,22 @@ compare_prepared_linux_kernel_packages(package& first_package,
|
||||
string vmlinux_path1, vmlinux_path2;
|
||||
|
||||
if (!get_vmlinux_path_from_kernel_dist(debug_dir1, vmlinux_path1))
|
||||
return abigail::tools_utils::ABIDIFF_ERROR;
|
||||
{
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Could not find vmlinux in debuginfo package '"
|
||||
<< first_package.path()
|
||||
<< "\n";
|
||||
return abigail::tools_utils::ABIDIFF_ERROR;
|
||||
}
|
||||
|
||||
if (!get_vmlinux_path_from_kernel_dist(debug_dir2, vmlinux_path2))
|
||||
return abigail::tools_utils::ABIDIFF_ERROR;
|
||||
{
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
<< "Could not find vmlinux in debuginfo package '"
|
||||
<< second_package.path()
|
||||
<< "\n";
|
||||
return abigail::tools_utils::ABIDIFF_ERROR;
|
||||
}
|
||||
|
||||
string dist_root1 = first_package.extracted_dir_path();
|
||||
string dist_root2 = second_package.extracted_dir_path();
|
||||
@@ -3044,14 +3217,24 @@ compare_prepared_linux_kernel_packages(package& first_package,
|
||||
|
||||
suppressions_type supprs;
|
||||
corpus_group_sptr corpus1, corpus2;
|
||||
|
||||
corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
|
||||
#ifdef WITH_CTF
|
||||
if (opts.use_ctf)
|
||||
requested_fe_kind = corpus::CTF_ORIGIN;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
if (opts.use_btf)
|
||||
requested_fe_kind = corpus::BTF_ORIGIN;
|
||||
#endif
|
||||
|
||||
corpus1 = build_corpus_group_from_kernel_dist_under(dist_root1,
|
||||
debug_dir1,
|
||||
vmlinux_path1,
|
||||
opts.suppression_paths,
|
||||
opts.kabi_whitelist_paths,
|
||||
supprs,
|
||||
opts.verbose,
|
||||
env);
|
||||
supprs, opts.verbose,
|
||||
env, requested_fe_kind);
|
||||
|
||||
if (!corpus1)
|
||||
return abigail::tools_utils::ABIDIFF_ERROR;
|
||||
@@ -3061,9 +3244,8 @@ compare_prepared_linux_kernel_packages(package& first_package,
|
||||
vmlinux_path2,
|
||||
opts.suppression_paths,
|
||||
opts.kabi_whitelist_paths,
|
||||
supprs,
|
||||
opts.verbose,
|
||||
env);
|
||||
supprs, opts.verbose,
|
||||
env, requested_fe_kind);
|
||||
|
||||
if (!corpus2)
|
||||
return abigail::tools_utils::ABIDIFF_ERROR;
|
||||
@@ -3117,7 +3299,7 @@ compare_prepared_package(package& first_package, package& second_package,
|
||||
{
|
||||
abidiff_status status = abigail::tools_utils::ABIDIFF_OK;
|
||||
|
||||
if (abigail::tools_utils::file_is_kernel_package(first_package.base_name(),
|
||||
if (abigail::tools_utils::file_is_kernel_package(first_package.path(),
|
||||
first_package.type()))
|
||||
{
|
||||
opts.show_symbols_not_referenced_by_debug_info = false;
|
||||
@@ -3434,6 +3616,10 @@ parse_command_line(int argc, char* argv[], options& opts)
|
||||
#ifdef WITH_CTF
|
||||
else if (!strcmp(argv[i], "--ctf"))
|
||||
opts.use_ctf = true;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
else if (!strcmp(argv[i], "--btf"))
|
||||
opts.use_btf = true;
|
||||
#endif
|
||||
else if (!strcmp(argv[i], "--help")
|
||||
|| !strcmp(argv[i], "-h"))
|
||||
@@ -3631,14 +3817,14 @@ main(int argc, char* argv[])
|
||||
| abigail::tools_utils::ABIDIFF_ERROR);
|
||||
}
|
||||
|
||||
if (file_is_kernel_package(first_package->base_name(),
|
||||
if (file_is_kernel_package(first_package->path(),
|
||||
abigail::tools_utils::FILE_TYPE_RPM)
|
||||
|| file_is_kernel_package(second_package->base_name(),
|
||||
|| file_is_kernel_package(second_package->path(),
|
||||
abigail::tools_utils::FILE_TYPE_RPM))
|
||||
{
|
||||
if (file_is_kernel_package(first_package->base_name(),
|
||||
if (file_is_kernel_package(first_package->path(),
|
||||
abigail::tools_utils::FILE_TYPE_RPM)
|
||||
!= file_is_kernel_package(second_package->base_name(),
|
||||
!= file_is_kernel_package(second_package->path(),
|
||||
abigail::tools_utils::FILE_TYPE_RPM))
|
||||
{
|
||||
emit_prefix("abipkgdiff", cerr)
|
||||
@@ -3716,6 +3902,8 @@ main(int argc, char* argv[])
|
||||
| abigail::tools_utils::ABIDIFF_ERROR);
|
||||
}
|
||||
|
||||
abigail::tools_utils::initialize();
|
||||
|
||||
if (opts.self_check)
|
||||
return compare_to_self(first_package, opts);
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2013-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 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-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
|
||||
+21
-33
@@ -3,7 +3,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- Mode: Python
|
||||
#
|
||||
# Copyright (C) 2013-2016 Red Hat, Inc.
|
||||
# Copyright (C) 2013-2023 Red Hat, Inc.
|
||||
#
|
||||
# Author: Chenxiong Qi
|
||||
|
||||
@@ -20,6 +20,7 @@ import shutil
|
||||
import six
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
from collections import namedtuple
|
||||
from itertools import chain
|
||||
@@ -29,6 +30,9 @@ import xdg.BaseDirectory
|
||||
import rpm
|
||||
import koji
|
||||
|
||||
from timeit import default_timer as timer
|
||||
from datetime import timedelta
|
||||
|
||||
# @file
|
||||
#
|
||||
# You might have known that abipkgdiff is a command line tool to compare two
|
||||
@@ -260,8 +264,12 @@ def log_call(func):
|
||||
func.__name__,
|
||||
args if args else '',
|
||||
kwargs if kwargs else '')
|
||||
start = timer()
|
||||
result = func(*args, **kwargs)
|
||||
logger.debug('Result from %s: %s', func.__name__, result)
|
||||
end = timer();
|
||||
elapsed_type = timedelta(seconds=end-start)
|
||||
logger.debug('Result from %s: %s, in: %s',
|
||||
func.__name__, result, elapsed_type)
|
||||
return result
|
||||
return proxy
|
||||
|
||||
@@ -612,26 +620,18 @@ def generate_comparison_halves(rpm_col1, rpm_col2):
|
||||
debuginfo_list1 = []
|
||||
debuginfo_list2 = []
|
||||
|
||||
# If this is a *devel* package we are looking at, then get all
|
||||
# the debug info packages associated to with the main package
|
||||
# and stick them into the resulting comparison half.
|
||||
|
||||
if _rpm.is_devel:
|
||||
debuginfo_list1 = rpm_col1.get_all_debuginfo_rpms(_rpm)
|
||||
else:
|
||||
debuginfo_list1.append(rpm_col1.get_matching_debuginfo(_rpm))
|
||||
# Get all debug info packages associated to with the main
|
||||
# package and stick them into the resulting comparison half.
|
||||
|
||||
debuginfo_list1 = rpm_col1.get_all_debuginfo_rpms(_rpm)
|
||||
devel1 = rpm_col1.get_sibling_devel(_rpm)
|
||||
|
||||
if global_config.self_compare:
|
||||
debuginfo_list2 = debuginfo_list1
|
||||
devel2 = devel1
|
||||
else:
|
||||
if rpm2.is_devel:
|
||||
debuginfo_list2 = rpm_col2.get_all_debuginfo_rpms(rpm2)
|
||||
else:
|
||||
debuginfo_list2.append(rpm_col2.get_matching_debuginfo(rpm2))
|
||||
devel2 = rpm_col2.get_sibling_devel(rpm2)
|
||||
debuginfo_list2 = rpm_col2.get_all_debuginfo_rpms(rpm2)
|
||||
devel2 = rpm_col2.get_sibling_devel(rpm2)
|
||||
|
||||
yield (ComparisonHalf(subject=_rpm,
|
||||
ancillary_debug=debuginfo_list1,
|
||||
@@ -659,6 +659,11 @@ class Brew(object):
|
||||
used to access koji XMLRPC APIs.
|
||||
"""
|
||||
self.session = koji.ClientSession(baseurl)
|
||||
# I am instructing the http client to avoid verifying SSL
|
||||
# certificates by default as some Koji server instance might
|
||||
# use self-signed certficates that can't be easily verified.
|
||||
if (hasattr(self.session, 'opts')):
|
||||
self.session.opts.setdefault('no_ssl_verify', True)
|
||||
|
||||
@log_call
|
||||
def listRPMs(self, buildID=None, arches=None, selector=None):
|
||||
@@ -1182,25 +1187,8 @@ def abipkgdiff(cmp_half1, cmp_half2):
|
||||
proc = subprocess.Popen(' '.join(cmd), shell=True,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
# So we could have done: stdout, stderr = proc.communicate()
|
||||
# But then the documentatin of proc.communicate says:
|
||||
#
|
||||
# Note: The data read is buffered in memory, so do not use this
|
||||
# method if the data size is large or unlimited. "
|
||||
#
|
||||
# In practice, we are seeing random cases where this
|
||||
# proc.communicate() function does *NOT* terminate and seems to be
|
||||
# in a deadlock state. So we are avoiding it altogether. We are
|
||||
# then busy looping, waiting for the spawn process to finish, and
|
||||
# then we get its output.
|
||||
#
|
||||
|
||||
while True:
|
||||
if proc.poll() != None:
|
||||
break
|
||||
|
||||
stdout = ''.join(proc.stdout.readlines())
|
||||
stderr = ''.join(proc.stderr.readlines())
|
||||
stdout, stderr = proc.communicate()
|
||||
|
||||
is_ok = proc.returncode == ABIDIFF_OK
|
||||
is_internal_error = proc.returncode & ABIDIFF_ERROR or proc.returncode & ABIDIFF_USAGE_ERROR
|
||||
|
||||
+30
-4
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// -*- Mode: C++ -*-
|
||||
//
|
||||
// Copyright (C) 2017-2022 Red Hat, Inc.
|
||||
// Copyright (C) 2017-2023 Red Hat, Inc.
|
||||
//
|
||||
// Author: Dodji Seketeli
|
||||
|
||||
@@ -56,6 +56,7 @@ struct options
|
||||
bool display_version;
|
||||
bool verbose;
|
||||
bool missing_operand;
|
||||
bool perform_change_categorization;
|
||||
bool leaf_changes_only;
|
||||
bool show_hexadecimal_values;
|
||||
bool show_offsets_sizes_in_bits;
|
||||
@@ -63,6 +64,9 @@ struct options
|
||||
optional<bool> exported_interfaces_only;
|
||||
#ifdef WITH_CTF
|
||||
bool use_ctf;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
bool use_btf;
|
||||
#endif
|
||||
string wrong_option;
|
||||
string kernel_dist_root1;
|
||||
@@ -81,6 +85,7 @@ struct options
|
||||
display_version(),
|
||||
verbose(),
|
||||
missing_operand(),
|
||||
perform_change_categorization(true),
|
||||
leaf_changes_only(true),
|
||||
show_hexadecimal_values(true),
|
||||
show_offsets_sizes_in_bits(false),
|
||||
@@ -88,6 +93,10 @@ struct options
|
||||
#ifdef WITH_CTF
|
||||
,
|
||||
use_ctf(false)
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
,
|
||||
use_btf(false)
|
||||
#endif
|
||||
{}
|
||||
}; // end struct options.
|
||||
@@ -118,6 +127,11 @@ display_usage(const string& prog_name, ostream& out)
|
||||
#ifdef WITH_CTF
|
||||
<< " --ctf use CTF instead of DWARF in ELF files\n"
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
<< " --btf use BTF instead of DWARF in ELF files\n"
|
||||
#endif
|
||||
<< " --no-change-categorization | -x don't perform categorization "
|
||||
"of changes, for speed purposes\n"
|
||||
<< " --impacted-interfaces|-i show interfaces impacted by ABI changes\n"
|
||||
<< " --full-impact|-f show the full impact of changes on top-most "
|
||||
"interfaces\n"
|
||||
@@ -260,6 +274,13 @@ parse_command_line(int argc, char* argv[], options& opts)
|
||||
else if (!strcmp(argv[i], "--ctf"))
|
||||
opts.use_ctf = true;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
else if (!strcmp(argv[i], "--btf"))
|
||||
opts.use_btf = true;
|
||||
#endif
|
||||
else if (!strcmp(argv[i], "--no-change-categorization")
|
||||
|| !strcmp(argv[i], "-x"))
|
||||
opts.perform_change_categorization = false;
|
||||
else if (!strcmp(argv[i], "--impacted-interfaces")
|
||||
|| !strcmp(argv[i], "-i"))
|
||||
opts.show_impacted_interfaces = true;
|
||||
@@ -330,6 +351,7 @@ set_diff_context(diff_context_sptr ctxt, const options& opts)
|
||||
ctxt->show_linkage_names(false);
|
||||
ctxt->show_symbols_unreferenced_by_debug_info
|
||||
(true);
|
||||
ctxt->perform_change_categorization(opts.perform_change_categorization);
|
||||
ctxt->show_leaf_changes_only(opts.leaf_changes_only);
|
||||
ctxt->show_impacted_interfaces(opts.show_impacted_interfaces);
|
||||
ctxt->show_hex_values(opts.show_hexadecimal_values);
|
||||
@@ -421,11 +443,15 @@ main(int argc, char* argv[])
|
||||
|
||||
corpus_group_sptr group1, group2;
|
||||
string debug_info_root_dir;
|
||||
corpus::origin requested_fe_kind =
|
||||
corpus::origin requested_fe_kind = corpus::DWARF_ORIGIN;
|
||||
#ifdef WITH_CTF
|
||||
opts.use_ctf ? corpus::CTF_ORIGIN :
|
||||
if (opts.use_ctf)
|
||||
requested_fe_kind = corpus::CTF_ORIGIN;
|
||||
#endif
|
||||
#ifdef WITH_BTF
|
||||
if (opts.use_btf)
|
||||
requested_fe_kind = corpus::BTF_ORIGIN;
|
||||
#endif
|
||||
corpus::DWARF_ORIGIN;
|
||||
|
||||
if (!opts.kernel_dist_root1.empty())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user