mirror of
git://sourceware.org/git/libabigail.git
synced 2024-12-18 07:54:36 +00:00
98c8d61684
This patch allows dropping suppressed ABI artifacts from the in-memory internal representation right during the DWARF or abixml reading. In practise, this means that abidw and abilint now have a --suppressions options to give them suppression specifications. If a suppression specification that has the "drop" property matches an ABI artifact (type, function or variable) then that artifact is dropped from the internal representation. This also applies to abidiff. Note that now, by default, ABI artifacts (types) that are suppressed due to the --headers-dir{1,2} option of abidiff are now also dropped from the IR as well. Incidentally, abidw and abilint tools now have a --header-dir option too. * doc/manuals/abidw.rst: Document the new --suppressions and --headers-dir options off the abidw tool. * doc/manuals/abilint.rst: Document the new --suppressions and --headers-dir options on the abilint tool. * doc/manuals/libabigail-concepts.rst: Document the new "drop" and "name_not_regexp" properties on suppression directives. * include/abg-corpus.h (corpus::corpus): Add a default argument to the path parameter. * src/abg-suppression-priv.h: New private header file. * src/Makefile.am: Add the new abg-suppression-priv.h file to source distribution. * include/abg-suppression.h ({suppression_base, type_suppression, function_suppression, variable_suppression}::priv): Make these public. (suppression_base::{g,s}et_drops_artifact_from_ir): Declare new member functions. (type_suppression::{suppressed_type}): Likewise. (suppression_base::{names,sonames}_of_binaries_match): Remove member functions. (function_suppression::{get_name, set_name, get_name_regex_str, set_name_regex_str}): Renamed get_function_name, set_function_name, get_function_name_regex_str, set_function_name_regex_str into these. ({variable,function}_suppression::{g,s}et_name_not_regex_str): Declare new member functions. * src/abg-suppression.cc: Include the new abg-suppression-priv.h private header. (class suppression_base::priv, class type_suppression::priv, class function_suppression::parameter_spec::priv, class function_suppression::priv, class variable_suppression::priv): Move these types to that new private header. (suppression_base::{g,s}et_drops_artifact_from_ir) (function_suppression::{g,s}et_name_not_regex_str) (variable_suppression::{g,s}et_name_not_regex_str): New member functions. (sonames_of_binaries_match): New static function, taken from suppression_base::sonames_of_binaries_match. (names_of_binaries_match): New static function, taken from suppression_base::names_of_binaries_match. (suppression_matches_type_no_name): New static function. (type_suppression::suppresses_type): Adjust (function_suppression::suppresses_function) (variable_suppression::suppresses_variable): Adjust. Evaluate the new "name_not_regexp" property. (suppression_matches_type_name) (suppression_matches_type_location) (suppression_matches_type_name_or_location) (suppression_matches_function_name) (suppression_matches_function_sym_name) (suppression_matches_variable_name) (suppression_matches_variable_sym_name, suppression_matches_type): New functions. (read_type_suppression): Support the new "drop_artifacts" and "drop" properties. (read_function_suppression, read_variable_suppression): Support the new "drop_artifacts", "drop", and "name_not_regexp" properties. (function_suppression::{g,s}et_name): Renamed {g,s}et_function_name into these. (function_suppression::set_name_not_regex_str): Renamed {g,s}et_name_regex_str into this. (function_suppression::suppresses_function_symbol): Adjust. * include/abg-dwarf-reader.h (add_read_context_suppressions): Declare new function. * src/abg-dwarf-reader.cc: Use the new private abg-suppression-priv.h header file. (read_context::supprs_): New data member. (read_context::get_suppressions): New member function. (read_context::get_die_source): Make this const. (read_context::tu_die_imported_unit_points_map): Add a const overload. (read_context::cur_transl_unit): Renamed current_translation_unit unit into this; (read_context::cur_tu): Remove or rename into cur_transl_unit. (get_scope_for_die, build_translation_unit_and_add_to_ir) (build_enum_type, build_pointer_type_def, build_reference_type) (build_function_type, build_array_type, build_function_decl): Adjust. (read_context::{suppression_can_match, suppression_matches_function_sym_name, suppression_matches_function_name, suppression_matches_variable_sym_name, suppression_matches_variable_name, suppression_matches_type_name_or_location, suppression_matches_type_name}): Add member functions. (die_signed_constant_attribute): Remove this as dead code. (die_location, die_loc_and_name) (find_import_unit_point_between_dies) (find_import_unit_point_before_die, get_parent_die): Make the read_context& parameter be const and adjust as required. (build_var_decl_if_not_suppressed, function_is_suppressed) (variable_is_suppressed, type_is_suppressed): Define new static functions. (add_read_context_suppressions): Define new function. (build_class_type_and_add_to_ir): Do not add suppressed static data members to the IR. (build_ir_node_from_die): Do not add suppressed enum types, class types, variables or functions to the IR. Adjust for the read_context::cur_tu -> read_context::cur_transl_unit rename. * include/abg-reader.h (read_context_sptr): Declare new type. (create_native_xml_read_context, read_corpus_from_input) (add_read_context_suppressions): Declare new functions. * src/abg-reader.cc: Include the new private abg-suppression-priv.h header file. (read_context::m_exported_decls_builder): Renamed m_exported_decls_builder_ into this. (read_context::get_exported_decls_builder): Adjust. (read_context::get_cur_scope): Make this const. (read_location): Take a const read_context and adjust. (read_corpus_from_input): Make this non-static. (build_namespace_decl): Don't abort if trying to add an artifact to the IR doesn't succeed. It might be suppressed now. (read_context::{m_path, m_supprs}): New data members. (read_context::{g,s}et_path): New member functions. (read_context::{get_suppressions, suppression_matches_function_name, suppression_can_match, suppression_matches_function_name, suppression_matches_function_sym_name, suppression_matches_variable_name, suppression_matches_variable_sym_name, suppression_matches_type_name_or_location}): Likewise. (add_read_context_suppressions, create_native_xml_read_context) (read_corpus_from_native_xml): New functions. (build_function_decl_if_not_suppressed, function_is_suppressed) (type_is_suppressed, build_var_decl_if_not_suppressed) (variable_is_suppressed, build_enum_type_decl_if_not_suppressed) (build_class_decl_if_not_suppressed): New static functions. (build_class_decl): Add member types that are being built early, so that their sub-types can be evaluated for suppression. Do not add suppressed static data members or suppressed member functions to the IR. (build_type): Do not add an enum type or a class type to the IR if they are suppressed. (handle_enum_type_decl): Do not add an enum type to the IR if its suppressed. (handle_var_decl): Likewise for a variable decl. (handle_function_decl): Likewise for a function decl. (handle_class_decl): Likewise for a class decl. * src/abg-tools-utils.cc (handle_fts_entry): Drop suppressed ABI from the IR. * tools/abidiff.cc (display_usage): Fix help strings for --headers-dirs{1,2}. (set_suppressions): New static function. (main): Adjust. Release the memory used by read_context early. * tools/abidw.cc (options::{headers_dir, suppression_paths}): (display_usage): New help strings for the new --header-dir and --suppressions options. (parse_command_line): Parse the new --header-dir and --suppressions options. (maybe_check_suppression_files, set_suppressions): New static functions. (main): Use the two new functions above. Free the memory used by the read context before working with the corpus. * tools/abilint.cc (options::suppression_paths): (display_usage): New help strings for the new --header-dir and --suppressions options. (parse_command_line): Parse the new --header-dir and --suppressions options. (maybe_check_suppression_files, set_suppressions): New static functions. (main): Use the two new functions above. Free the memory used by the read context before working with the corpus. * tests/data/test-diff-suppr/test24-soname-suppr-{2,3].txt: Adjust. * tests/data/test-diff-suppr/test29-suppr-6.txt: Likewise. * tests/data/test-diff-suppr/test29-suppr-8.txt: Likewise. * tests/data/test-diff-suppr/libtest31-v{0,1}.so: New test input. * tests/data/test-diff-suppr/libtest31.suppr: Likewise * tests/data/test-diff-suppr/libtest32-v{0,1}.so: Likewise. * tests/data/test-diff-suppr/libtest32-0.suppr: Likewise. * tests/data/test-diff-suppr/libtest33-v{0,1}.so: Likewise. * tests/data/test-diff-suppr/test31-report-{0,1}.txt: Likewise. * tests/data/test-diff-suppr/test31-v{0,1}.cc: Likewise. * tests/data/test-diff-suppr/test32-report-{0,1}.txt: Likewise. * tests/data/test-diff-suppr/test32-v{0,1}.c: Likewise. * tests/data/test-diff-suppr/test33-suppr-1.txt: Likewise. * tests/data/test-diff-suppr/test33-v{0,1}.cc: Likewise. * tests/data/test-diff-suppr/test33-v{0,1}.h: Likewise. * tests/data/test-read-dwarf/libtest24-drop-fns-2.so.abi: Likewise. * tests/data/test-read-dwarf/libtest24-drop-fns.so: Likewise. * tests/data/test-read-dwarf/libtest24-drop-fns.so.abi: Likewise. * tests/data/test-read-dwarf/test24-drop-fns-0.suppr: Likewise. * tests/data/test-read-dwarf/test24-drop-fns.cc: Likewise. * tests/data/test-read-write/test28-drop-std-fns.abignore: Likewise. * tests/data/test-read-write/test28-drop-std-vars.abignore: Likewise. * tests/data/test-read-write/test28-without-std-fns-ref.xml: Likewise. * tests/data/test-read-write/test28-without-std-fns.xml: Likewise. * tests/data/test-read-write/test28-without-std-vars-ref.xml: Likewise. * tests/data/test-read-write/test28-without-std-vars.xml: Likewise. * tests/data/test-read-write/test28.xml: Likewise. * tests/data/Makefile.am: Add the new test artifacts to source distribution. * tests/test-diff-suppr.cc (in_out_spec): Take the new test inputs into account. * tests/test-read-dwarf.cc (Inoutspec::in_suppr_spec_path): New data member. (in_out_spec): Adjust. The new test inputs into account. (set_suppressions): New static function. (handle_in_out_spec): Adjust. * tests/test-read-write.cc (Inoutspec::{in_suppr_spec_path, ref_out_path}): New data members. (in_out_spec): Adjust. Take new test inputs into account. (main): Adjust. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
1606 lines
46 KiB
ReStructuredText
1606 lines
46 KiB
ReStructuredText
#########
|
|
Concepts
|
|
#########
|
|
|
|
.. _abi_artifacts_label:
|
|
|
|
ABI artifacts
|
|
=============
|
|
|
|
An ABI artifact is a relevant part of the ABI of a shared library or
|
|
program. Examples of ABI artifacts are exported types, variables,
|
|
functions, or `ELF`_ symbols exported by a shared library.
|
|
|
|
The set of ABI artifact for a binary is called an ABI Corpus.
|
|
|
|
.. _harmfulchangeconcept_label:
|
|
|
|
Harmful changes
|
|
===============
|
|
|
|
A change in the diff report is considered harmful if it might cause
|
|
ABI compatibility issues. That is, it might prevent an application
|
|
dynamically linked against a given version of a library to keep
|
|
working with the changed subsequent versions of the same library.
|
|
|
|
.. _harmlesschangeconcept_label:
|
|
|
|
Harmless changes
|
|
================
|
|
|
|
A change in the diff report is considered harmless if it will not
|
|
cause any ABI compatibility issue. That is, it will not prevent an
|
|
application dynamically linked against given version of a library to
|
|
keep working with the changed subsequent versions of the same library.
|
|
|
|
By default, ``abidiff`` filters harmless changes from the diff report.
|
|
|
|
.. _suppr_spec_label:
|
|
|
|
Suppression specifications
|
|
==========================
|
|
|
|
|
|
Definition
|
|
----------
|
|
|
|
A suppression specification file is a way for a user to instruct
|
|
:ref:`abidiff <abidiff_label>`, :ref:`abipkgdiff <abipkgdiff_label>`
|
|
or any other relevant libabigail tool to avoid emitting reports for
|
|
changes involving certain :ref:`ABI artifacts<abi_artifacts_label>`.
|
|
|
|
It contains directives (or specifications) that describe the set of
|
|
ABI artifacts to avoid emitting change reports about.
|
|
|
|
Introductory examples
|
|
---------------------
|
|
|
|
Its syntax is based on a simplified and customized form of `Ini File
|
|
Syntax`_. For instance, to specify that change reports on a type
|
|
named FooPrivateType should be suppressed, one could write this
|
|
suppression specification: ::
|
|
|
|
[suppress_type]
|
|
name = FooPrivateType
|
|
|
|
If we want to ensure that only change reports about structures named
|
|
FooPrivateType should be suppressed, we could write: ::
|
|
|
|
[suppress_type]
|
|
type_kind = struct
|
|
name = FooPrivateType
|
|
|
|
But we could also want to suppress change reports avoid typedefs named
|
|
FooPrivateType. In that case we would write: ::
|
|
|
|
[suppress_type]
|
|
type_kind = typedef
|
|
name = FooPrivateType
|
|
|
|
Or, we could want to suppress change reports about all struct which
|
|
names end with the string "PrivateType": ::
|
|
|
|
[suppress_type]
|
|
type_kind = struct
|
|
name_regexp = ^.*PrivateType
|
|
|
|
Let's now look at the generic syntax of suppression specification
|
|
files.
|
|
|
|
Syntax
|
|
------
|
|
|
|
Properties
|
|
^^^^^^^^^^
|
|
|
|
More generally, the format of suppression lists is organized around
|
|
the concept of `property`. Every property has a name and a value,
|
|
delimited by the ``=`` sign. E.g: ::
|
|
|
|
name = value
|
|
|
|
Leading and trailing white spaces are ignored around property names
|
|
and values.
|
|
|
|
.. _suppr_regexp_label:
|
|
|
|
Regular expressions
|
|
^^^^^^^^^^^^^^^^^^^
|
|
|
|
The value of some properties might be a regular expression. In that
|
|
case, they must comply with the syntax of `extended POSIX regular
|
|
expressions
|
|
<http://www.gnu.org/software/findutils/manual/html_node/find_html/posix_002dextended-regular-expression-syntax.html#posix_002dextended-regular-expression-syntax>`_.
|
|
Note that Libabigail uses the regular expression engine of the `GNU C
|
|
Library`_.
|
|
|
|
Escaping a character in a regular expression
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
When trying to match a string that contains a ``*`` character, like in
|
|
the pointer type ``int*``, one must be careful to notice that the
|
|
character ``*`` is a special character in the extended POSIX regular
|
|
expression syntax. And that character must be escaped for the regular
|
|
expression engine. Thus the regular expression that would match the
|
|
string ``int*`` in a suppression file should be ::
|
|
|
|
int\\*
|
|
|
|
Wait; but then why the two ``\`` characters? Well, because the ``\``
|
|
character is a special character in the `Ini File Syntax`_ used for
|
|
specifying suppressions. So it must be escaped as well, so that the
|
|
Ini File parser leaves a ``\`` character intact in the data stream
|
|
that is handed to the regular expression engine. Hence the ``\\``
|
|
targeted at the Ini File parser.
|
|
|
|
So, in short, to escape a character in a regular expression, always
|
|
prefix the character with the ``\\`` sequence.
|
|
|
|
Modus operandi
|
|
^^^^^^^^^^^^^^
|
|
|
|
|
|
Suppression specifications can be applied at two different points of
|
|
the processing pipeline of libabigail.
|
|
|
|
.. _late_suppression_mode_label:
|
|
|
|
In the default operating mode called "late suppression mode",
|
|
suppression specifications are applied to the result of comparing the
|
|
in-memory internal representations of two ABIs. In this mode, if an
|
|
ABI artifact matches a suppression specification, its changes are not
|
|
mentioned in the ABI change report. The internal representation of
|
|
the "suppressed" changed ABI artifact is still present in memory; it
|
|
is just not mentioned in the ABI change report. The change report can
|
|
still mention statistics about the number of changed ABI artifacts
|
|
that were suppressed.
|
|
|
|
.. _early_suppression_mode_label:
|
|
|
|
There is another operating mode called the "early suppression mode"
|
|
where suppression specifications are applied during the construction
|
|
of the in-memory internal representation of a given ABI. In that
|
|
mode, if an ABI artifact matches a suppression specification, no
|
|
in-memory internal representation is built for it. As a result, no
|
|
change about the matched ABI artifact is going to be mentioned in the
|
|
ABI change report and no statistic about the number of suppressed ABI
|
|
changes is available. Also, please note that because suppressed ABI
|
|
artifacts are removed from the in-memory internal representation in
|
|
this mode, the amount memory used by the internal representation is
|
|
potentially smaller than the memory consumption in the late
|
|
suppression mode.
|
|
|
|
Sections
|
|
^^^^^^^^
|
|
|
|
Properties are then grouped into arbitrarily named sections that shall
|
|
not be nested. The name of the section is on a line by itself and is
|
|
surrounded by square brackets, i.e: ::
|
|
|
|
[section_name]
|
|
property1_name = property1_value
|
|
property2_name = property2_value
|
|
|
|
|
|
A section might or might not have properties. Sections that expect to
|
|
have properties and which are found nonetheless empty are just
|
|
ignored. Properties that are not recognized by the reader are ignored
|
|
as well.
|
|
|
|
Section names
|
|
^^^^^^^^^^^^^
|
|
|
|
Each different section can be thought of as being a directive to
|
|
suppress ABI change reports for a particular kind of ABI artifact.
|
|
|
|
``[suppress_file]``
|
|
$$$$$$$$$$$$$$$$$$$
|
|
|
|
This directive prevents a given tool from loading a file (binary or
|
|
not) if its file name matches certain properties. Thus, if the tool
|
|
is meant to compare the ABIs of two files, and if the directive
|
|
prevents it from loading either one of the files, then no comparison
|
|
is performed.
|
|
|
|
Note that for the ``[suppress_file]`` directive to work, at least one
|
|
of the following properties must be provided:
|
|
|
|
``file_name_regexp``, ``file_name_not_regexp``.
|
|
|
|
The potential properties of this sections are listed below:
|
|
|
|
* ``file_name_regexp``
|
|
|
|
Usage:
|
|
|
|
``file_name_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Prevents the system from loading the file which name matches the
|
|
regular expression specified as value of this property.
|
|
|
|
* ``file_name_not_regexp``
|
|
|
|
Usage:
|
|
|
|
``file_name_not_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Prevents the system from loading the file which name does not match
|
|
the regular expression specified as value of this property.
|
|
|
|
|
|
* ``label``
|
|
|
|
Usage:
|
|
|
|
``label`` ``=`` <some-value>
|
|
|
|
Define a label for the section. A label is just an informative
|
|
string that might be used by the tool to refer to a type suppression
|
|
in error messages.
|
|
|
|
``[suppress_type]``
|
|
$$$$$$$$$$$$$$$$$$$
|
|
|
|
This directive suppresses report messages about a type change.
|
|
|
|
Note that for the ``[suppress_type]`` directive to work, at least one
|
|
of the following properties must be provided:
|
|
|
|
``file_name_regexp``, ``file_name_not_regexp``, ``soname_regexp``,
|
|
``soname_not_regexp``, ``name``, ``name_regexp``, ``type_kind``,
|
|
``source_location_not_in``, ``source_location_not_regexp``.
|
|
|
|
If none of the following properties are provided, then the
|
|
``[suppress_type]`` directive is simply ignored.
|
|
|
|
The potential properties of this sections are listed below:
|
|
|
|
* ``file_name_regexp``
|
|
|
|
Usage:
|
|
|
|
``file_name_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports about ABI artifacts that are defined in a
|
|
binary file which name matches the regular expression specified as
|
|
value of this property.
|
|
|
|
* ``file_name_not_regexp``
|
|
|
|
Usage:
|
|
|
|
``file_name_not_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports about ABI artifacts that are defined in a
|
|
binary file which name does not match the regular expression
|
|
specified as value of this property.
|
|
|
|
|
|
* ``soname_regexp``
|
|
|
|
Usage:
|
|
|
|
``soname_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports about ABI artifacts that are defined in a
|
|
shared library which SONAME property matches the regular expression
|
|
specified as value of this property.
|
|
|
|
* ``soname_not_regexp``
|
|
|
|
Usage:
|
|
|
|
``soname_not_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports about ABI artifacts that are defined in a
|
|
shared library which SONAME property does not match the regular
|
|
expression specified as value of this property.
|
|
|
|
* ``name_regexp``
|
|
|
|
Usage:
|
|
|
|
``name_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports involving types whose name matches the
|
|
regular expression specified as value of this property.
|
|
|
|
* ``name``
|
|
|
|
Usage:
|
|
|
|
``name`` ``=`` <a-value>
|
|
|
|
Suppresses change reports involving types whose name equals the value
|
|
of this property.
|
|
|
|
* ``type_kind``
|
|
|
|
Usage:
|
|
|
|
``type_kind`` ``=`` ``class`` | ``struct`` | ``union`` | ``enum`` |
|
|
``array`` | ``typedef`` | ``builtin``
|
|
|
|
Suppresses change reports involving a certain kind of type. The kind
|
|
of type to suppress change reports for is specified by the possible
|
|
values listed above:
|
|
|
|
- ``class``: suppress change reports for class types. Note that
|
|
even if class types don't exist for C, this value still
|
|
triggers the suppression of change reports for struct types,
|
|
in C. In C++ however, it should do what it suggests.
|
|
|
|
- ``struct``: suppress change reports for struct types in C or C++.
|
|
Note that the value ``class`` above is a super-set of this
|
|
one.
|
|
|
|
- ``union``: suppress change reports for union types.
|
|
|
|
- ``enum``: suppress change reports for enum types.
|
|
|
|
- ``array``: suppress change reports for array types.
|
|
|
|
- ``typedef``: suppress change reports for typedef types.
|
|
|
|
- ``builtin``: suppress change reports for built-in (or native)
|
|
types. Example of built-in types are char, int, unsigned int,
|
|
etc.
|
|
|
|
.. _suppr_source_location_not_in_label:
|
|
|
|
* ``source_location_not_in``
|
|
|
|
Usage:
|
|
|
|
``source_location_not_in`` ``=`` <``list-of-file-paths``>
|
|
|
|
Suppresses change reports involving a type which is defined in a file
|
|
which path is *NOT* listed in the value ``list-of-file-paths``. Note
|
|
that the value is a comma-separated list of file paths e.g, this
|
|
property ::
|
|
|
|
source_location_not_in = libabigail/abg-ir.h, libabigail/abg-dwarf-reader.h
|
|
|
|
suppresses change reports about all the types that are *NOT* defined
|
|
in header files whose path end up with the strings
|
|
libabigail/abg-ir.h or libabigail/abg-dwarf-reader.h.
|
|
|
|
.. _suppr_source_location_not_regexp_label:
|
|
|
|
* ``source_location_not_regexp``
|
|
|
|
Usage:
|
|
|
|
``source_location_not_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports involving a type which is defined in a file
|
|
which path does *NOT* match the :ref:`regular expression
|
|
<suppr_regexp_label>` provided as value of the property. E.g, this
|
|
property ::
|
|
|
|
source_location_not_regexp = libabigail/abg-.*\\.h
|
|
|
|
suppresses change reports involving all the types that are *NOT*
|
|
defined in header files whose path match the regular expression
|
|
provided a value of the property.
|
|
|
|
.. _suppr_has_data_member_inserted_at_label:
|
|
|
|
* ``has_data_member_inserted_at``
|
|
|
|
Usage:
|
|
|
|
``has_data_member_inserted_at`` ``=`` <``offset-in-bit``>
|
|
|
|
Suppresses change reports involving a type which has at least one
|
|
data member inserted at an offset specified by the property value
|
|
``offset-in-bit``. The value ``offset-in-bit`` is either:
|
|
|
|
- an integer value, expressed in bits, which denotes the
|
|
offset of the insertion point of the data member, starting
|
|
from the beginning of the relevant structure or class.
|
|
|
|
- the keyword ``end`` which is a named constant which value
|
|
equals the offset of the end of the of the structure or
|
|
class.
|
|
|
|
- the function call expression
|
|
``offset_of(data-member-name)`` where `data-member-name` is
|
|
the name of a given data member of the relevant structure
|
|
or class. The value of this function call expression is an
|
|
integer that represents the offset of the data member
|
|
denoted by ``data-member-name``.
|
|
|
|
- the function call expression
|
|
``offset_after(data-member-name)`` where `data-member-name`
|
|
is the name of a given data member of the relevant
|
|
structure or class. The value of this function call
|
|
expression is an integer that represents the offset of the
|
|
point that comes right after the region occupied by the
|
|
data member denoted by ``data-member-name``.
|
|
|
|
.. _suppr_has_data_member_inserted_between_label:
|
|
|
|
|
|
* ``has_data_member_inserted_between``
|
|
|
|
Usage:
|
|
|
|
``has_data_member_inserted_between`` ``=`` {<``range-begin``>, <``range-end``>}
|
|
|
|
Suppresses change reports involving a type which has at least one
|
|
data mber inserted at an offset that is comprised in the range
|
|
between range-begin`` and ``range-end``. Please note that each of
|
|
the lues ``range-begin`` and ``range-end`` can be of the same form as
|
|
the :ref:`has_data_member_inserted_at
|
|
<suppr_has_data_member_inserted_at_label>` property above.
|
|
|
|
Usage examples of this properties are: ::
|
|
|
|
has_data_member_inserted_between = {8, 64}
|
|
|
|
or: ::
|
|
|
|
has_data_member_inserted_between = {16, end}
|
|
|
|
or: ::
|
|
|
|
has_data_member_inserted_between = {offset_after(member1), end}
|
|
|
|
.. _suppr_has_data_members_inserted_between_label:
|
|
|
|
|
|
* ``has_data_members_inserted_between``
|
|
|
|
Usage:
|
|
|
|
``has_data_members_inserted_between`` ``=`` {<sequence-of-ranges>}
|
|
|
|
Suppresses change reports involving a type which has multiple data
|
|
member inserted in various offset ranges. A usage example of this
|
|
property is, for instance: ::
|
|
|
|
has_data_members_inserted_between = {{8, 31}, {72, 95}}
|
|
|
|
This usage example suppresses change reports involving a type which
|
|
has data members inserted in bit offset ranges [8 31] and [72 95].
|
|
The length of the sequence of ranges or this
|
|
``has_data_members_inserted_between`` is not bounded; it can be as
|
|
long as the system can cope with. The values of the boundaries of
|
|
the ranges are of the same kind as for the
|
|
:ref:`has_data_member_inserted_at
|
|
<suppr_has_data_member_inserted_at_label>` property above.
|
|
|
|
Another usage example of this property is thus: ::
|
|
|
|
has_data_members_inserted_between =
|
|
{
|
|
{offset_after(member0), offset_of(member1)},
|
|
{72, end}
|
|
}
|
|
|
|
.. _suppr_accessed_through_property_label:
|
|
|
|
* ``accessed_through``
|
|
|
|
Usage:
|
|
|
|
``accessed_through`` ``=`` <some-predefined-values>
|
|
|
|
Suppress change reports involving a type which is referred to either
|
|
directly or through a pointer or a reference. The potential values
|
|
of this property are the predefined keywords below:
|
|
|
|
* ``direct``
|
|
|
|
So if the ``[suppress_type]`` contains the property
|
|
description: ::
|
|
|
|
accessed_through = direct
|
|
|
|
then changes about a type that is referred-to
|
|
directly (i.e, not through a pointer or a reference)
|
|
are going to be suppressed.
|
|
|
|
* ``pointer``
|
|
|
|
If the ``accessed_through`` property is set to the
|
|
value ``pointer`` then changes about a type that is
|
|
referred-to through a pointer are going to be
|
|
suppressed.
|
|
|
|
* ``reference``
|
|
|
|
If the ``accessed_through`` property is set to the
|
|
value ``reference`` then changes about a type that is
|
|
referred-to through a reference are going to be
|
|
suppressed.
|
|
|
|
* ``reference-or-pointer``
|
|
|
|
If the ``accessed_through`` property is set to the
|
|
value ``reference-or-pointer`` then changes about a
|
|
type that is referred-to through either a reference
|
|
or a pointer are going to be suppressed.
|
|
|
|
For an extensive example of how to use this property, please check
|
|
out the example below about :ref:`suppressing change reports about
|
|
types accessed either directly or through pointers
|
|
<example_accessed_through_label>`.
|
|
|
|
* ``drop``
|
|
|
|
Usage:
|
|
|
|
``drop`` ``=`` yes | no
|
|
|
|
If a type is matched by a suppression specification which contains
|
|
the "drop" property set to "yes" (or to "true") then the type is not
|
|
even going to be represented in the internal representation of the
|
|
ABI being analyzed. This property makes its enclosing suppression
|
|
specification to be applied in the :ref:`early suppression
|
|
specification mode <early_suppression_mode_label>`. The net effect
|
|
is that it potentially reduces the memory used to represent the ABI
|
|
being analyzed.
|
|
|
|
Please note that for this property to be effective, the enclosing
|
|
suppression specification must have at least one of the following
|
|
properties specified: ``name_regexp``, ``name``, ``name_regexp``,
|
|
``source_location_not_in`` or ``source_location_not_regexp``.
|
|
|
|
.. _suppr_label_property_label:
|
|
|
|
* ``label``
|
|
|
|
Usage:
|
|
|
|
``label`` ``=`` <some-value>
|
|
|
|
Define a label for the section. A label is just an informative
|
|
string that might be used by a tool to refer to a type suppression in
|
|
error messages.
|
|
|
|
``[suppress_function]``
|
|
$$$$$$$$$$$$$$$$$$$$$$$$
|
|
|
|
This directive suppresses report messages about changes on a set of
|
|
functions.
|
|
|
|
Note that for the ``[suppress_function]`` directive to work, at least
|
|
one of the following properties must be provided:
|
|
|
|
``label``, ``file_name_regexp``, ``file_name_not_regexp``,
|
|
``soname_regexp``, ``soname_not_regexp``, ``name``, ``name_regexp``,
|
|
``name_not_regexp``, ``parameter``, ``return_type_name``,
|
|
``symbol_name``, ``symbol_name_regexp``, ``symbol_version``,
|
|
``symbol_version_regexp``.
|
|
|
|
If none of the following properties are provided, then the
|
|
``[suppress_function]`` directive is simply ignored.
|
|
|
|
The potential properties of this sections are:
|
|
|
|
* ``label``
|
|
|
|
Usage:
|
|
|
|
``label`` ``=`` <some-value>
|
|
|
|
This property is the same as the :ref:`label property
|
|
<suppr_label_property_label>` defined above.
|
|
|
|
|
|
* ``file_name_regexp``
|
|
|
|
Usage:
|
|
|
|
``file_name_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports about ABI artifacts that are defined in a
|
|
binary file which name matches the regular expression specified as
|
|
value of this property.
|
|
|
|
|
|
* ``file_name_not_regexp``
|
|
|
|
Usage:
|
|
|
|
``file_name_not_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports about ABI artifacts that are defined in a
|
|
binary file which name does not match the regular expression
|
|
specified as value of this property.
|
|
|
|
* ``soname_regexp``
|
|
|
|
Usage:
|
|
|
|
``soname_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports about ABI artifacts that are defined in a
|
|
shared library which SONAME property matches the regular expression
|
|
specified as value of this property.
|
|
|
|
* ``soname_not_regexp``
|
|
|
|
Usage:
|
|
|
|
``soname_not_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports about ABI artifacts that are defined in a
|
|
shared library which SONAME property does not match the regular
|
|
expression specified as value of this property.
|
|
|
|
|
|
* ``name``
|
|
|
|
Usage:
|
|
|
|
``name`` ``=`` <some-value>
|
|
|
|
Suppresses change reports involving functions whose name equals the
|
|
value of this property.
|
|
|
|
* ``name_regexp``
|
|
|
|
Usage:
|
|
|
|
``name_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports involving functions whose name matches the
|
|
regular expression specified as value of this property.
|
|
|
|
Let's consider the case of functions that have several symbol names.
|
|
This happens when the underlying symbol for the function has
|
|
aliases. Each symbol name is actually one alias name.
|
|
|
|
In this case, if the regular expression matches the name of
|
|
at least one of the aliases names, then it must match the names of
|
|
all of the aliases of the function for the directive to actually
|
|
suppress the diff reports for said function.
|
|
|
|
|
|
* ``name_not_regexp``
|
|
|
|
Usage:
|
|
|
|
``name_not_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports involving functions whose names don't match
|
|
the regular expression specified as value of this property.
|
|
|
|
The rules for functions that have several symbol names are the same
|
|
rules as for the ``name_regexp`` property above.
|
|
|
|
.. _suppr_change_kind_property_label:
|
|
|
|
|
|
* ``change_kind``
|
|
|
|
Usage:
|
|
|
|
``change_kind`` ``=`` <predefined-possible-values>
|
|
|
|
Specifies the kind of changes this suppression specification should
|
|
apply to. The possible values of this property as well as their
|
|
meaning are listed below:
|
|
|
|
- ``function-subtype-change``
|
|
|
|
This suppression specification applies to functions
|
|
that which have at least one sub-type that has
|
|
changed.
|
|
|
|
- ``added-function``
|
|
|
|
This suppression specification applies to functions
|
|
that have been added to the binary.
|
|
|
|
- ``deleted-function``
|
|
|
|
This suppression specification applies to functions
|
|
that have been removed from the binary.
|
|
|
|
- ``all``
|
|
|
|
This suppression specification applies to functions
|
|
that have all of the changes above. Note that not
|
|
providing the ``change_kind`` property at all is
|
|
equivalent to setting it to the value ``all``.
|
|
|
|
|
|
* ``parameter``
|
|
|
|
Usage:
|
|
|
|
``parameter`` ``=`` <function-parameter-specification>
|
|
|
|
Suppresses change reports involving functions whose
|
|
parameters match the parameter specification indicated as
|
|
value of this property.
|
|
|
|
The format of the function parameter specification is:
|
|
|
|
``'`` ``<parameter-index>`` ``<space>`` ``<type-name-or-regular-expression>``
|
|
|
|
That is, an apostrophe followed by a number that is the
|
|
index of the parameter, followed by one of several spaces,
|
|
followed by either the name of the type of the parameter,
|
|
or a regular expression describing a family of parameter
|
|
type names.
|
|
|
|
If the parameter type name is designated by a regular
|
|
expression, then said regular expression must be enclosed
|
|
between two slashes; like ``/some-regular-expression/``.
|
|
|
|
The index of the first parameter of the function is zero.
|
|
Note that for member functions (methods of classes), the
|
|
this is the first parameter that comes after the implicit
|
|
"this" pointer parameter.
|
|
|
|
Examples of function parameter specifications are: ::
|
|
|
|
'0 int
|
|
|
|
Which means, the parameter at index 0, whose type name is
|
|
``int``. ::
|
|
|
|
'4 unsigned char*
|
|
|
|
Which means, the parameter at index 4, whose type name is
|
|
``unsigned char*``. ::
|
|
|
|
'2 /^foo.*&/
|
|
|
|
Which means, the parameter at index 2, whose type name
|
|
starts with the string "foo" and ends with an '&'. In
|
|
other words, this is the third parameter and it's a
|
|
reference on a type that starts with the string "foo".
|
|
|
|
* ``return_type_name``
|
|
|
|
Usage:
|
|
|
|
``return_type_name`` ``=`` <some-value>
|
|
|
|
Suppresses change reports involving functions whose return type name
|
|
equals the value of this property.
|
|
|
|
* ``return_type_regexp``
|
|
|
|
Usage:
|
|
|
|
``return_type_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports involving functions whose return type name
|
|
matches the regular expression specified as value of this property.
|
|
|
|
* ``symbol_name``
|
|
|
|
Usage:
|
|
|
|
``symbol_name`` ``=`` <some-value>
|
|
|
|
Suppresses change reports involving functions whose symbol name equals
|
|
the value of this property.
|
|
|
|
* ``symbol_name_regexp``
|
|
|
|
Usage:
|
|
|
|
``symbol_name_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports involving functions whose symbol name
|
|
matches the regular expression specified as value of this property.
|
|
|
|
Let's consider the case of functions that have several symbol names.
|
|
This happens when the underlying symbol for the function has
|
|
aliases. Each symbol name is actually one alias name.
|
|
|
|
In this case, the regular expression must match the names of all of
|
|
the aliases of the function for the directive to actually suppress
|
|
the diff reports for said function.
|
|
|
|
* ``symbol_version``
|
|
|
|
Usage:
|
|
|
|
``symbol_version`` ``=`` <some-value>
|
|
|
|
Suppresses change reports involving functions whose symbol version
|
|
equals the value of this property.
|
|
|
|
* ``symbol_version_regexp``
|
|
|
|
Usage:
|
|
|
|
``symbol_version_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports involving functions whose symbol version
|
|
matches the regular expression specified as value of this property.
|
|
|
|
* ``drop``
|
|
|
|
Usage:
|
|
|
|
``drop`` ``=`` yes | no
|
|
|
|
If a function is matched by a suppression specification which
|
|
contains the "drop" property set to "yes" (or to "true") then the
|
|
function is not even going to be represented in the internal
|
|
representation of the ABI being analyzed. This property makes its
|
|
enclosing suppression specification to be applied in the :ref:`early
|
|
suppression specification mode <early_suppression_mode_label>`. The
|
|
net effect is that it potentially reduces the memory used to
|
|
represent the ABI being analyzed.
|
|
|
|
Please note that for this property to be effective, the enclosing
|
|
suppression specification must have at least one of the following
|
|
properties specified: ``name_regexp``, ``name``, ``name_regexp``,
|
|
``source_location_not_in`` or ``source_location_not_regexp``.
|
|
|
|
``[suppress_variable]``
|
|
$$$$$$$$$$$$$$$$$$$$$$$$
|
|
|
|
This directive suppresses report messages about changes on a set of
|
|
variables.
|
|
|
|
Note that for the ``[suppress_variable]`` directive to work, at least
|
|
one of the following properties must be provided:
|
|
|
|
``label``, ``file_name_regexp``, ``file_name_not_regexp``,
|
|
``soname_regexp``, ``soname_not_regexp``, ``name``, ``name_regexp``,
|
|
``symbol_name``, ``symbol_name_regexp``, ``symbol_version``,
|
|
``symbol_version_regexp``.
|
|
|
|
If none of the following properties are provided, then the
|
|
``[suppres_variable]`` directive is simply ignored.
|
|
|
|
The potential properties of this sections are:
|
|
|
|
* ``label``
|
|
|
|
Usage:
|
|
|
|
``label`` ``=`` <some-value>
|
|
|
|
This property is the same as the :ref:`label property
|
|
<suppr_label_property_label>` defined above.
|
|
|
|
|
|
* ``file_name_regexp``
|
|
|
|
Usage:
|
|
|
|
``file_name_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports about ABI artifacts that are defined in a
|
|
binary file which name matches the regular expression specified as
|
|
value of this property.
|
|
|
|
* ``file_name_not_regexp``
|
|
|
|
Usage:
|
|
|
|
``file_name_not_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports about ABI artifacts that are defined in a
|
|
binary file which name does not match the regular expression
|
|
specified as value of this property.
|
|
|
|
|
|
* ``soname_regexp``
|
|
|
|
Usage:
|
|
|
|
``soname_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports about ABI artifacts that are defined in a
|
|
shared library which SONAME property matches the regular expression
|
|
specified as value of this property.
|
|
|
|
|
|
* ``soname_not_regexp``
|
|
|
|
Usage:
|
|
|
|
``soname_not_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports about ABI artifacts that are defined in a
|
|
shared library which SONAME property does not match the regular
|
|
expression specified as value of this property.
|
|
|
|
|
|
* ``name``
|
|
|
|
Usage:
|
|
|
|
``name`` ``=`` <some-value>
|
|
|
|
Suppresses change reports involving variables whose name equals the
|
|
value of this property.
|
|
|
|
* ``name_regexp``
|
|
|
|
Usage:
|
|
|
|
``name_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports involving variables whose name matches the
|
|
regular expression specified as value of this property.
|
|
|
|
* ``change_kind``
|
|
|
|
Usage:
|
|
|
|
``change_kind`` ``=`` <predefined-possible-values>
|
|
|
|
Specifies the kind of changes this suppression specification should
|
|
apply to. The possible values of this property as well as their
|
|
meaning are the same as when it's :ref:`used in the
|
|
[suppress_function] section <suppr_change_kind_property_label>`.
|
|
|
|
* ``symbol_name``
|
|
|
|
Usage:
|
|
|
|
``symbol_name`` ``=`` <some-value>
|
|
|
|
Suppresses change reports involving variables whose symbol name equals
|
|
the value of this property.
|
|
|
|
* symbol_name_regexp
|
|
|
|
Usage:
|
|
|
|
``symbol_name_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports involving variables whose symbol name
|
|
matches the regular expression specified as value of this property.
|
|
|
|
|
|
* ``symbol_version``
|
|
|
|
Usage:
|
|
|
|
``symbol_version`` ``=`` <some-value>
|
|
|
|
Suppresses change reports involving variables whose symbol version
|
|
equals the value of this property.
|
|
|
|
* ``symbol_version_regexp``
|
|
|
|
Usage:
|
|
|
|
``symbol_version_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports involving variables whose symbol version
|
|
matches the regular expression specified as value of this property.
|
|
|
|
* ``type_name``
|
|
|
|
Usage:
|
|
|
|
``type_name`` ``=`` <some-value>
|
|
|
|
Suppresses change reports involving variables whose type name equals
|
|
the value of this property.
|
|
|
|
* ``type_name_regexp``
|
|
|
|
Usage:
|
|
|
|
``type_name_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
|
|
|
|
Suppresses change reports involving variables whose type name matches
|
|
the regular expression specified as value of this property.
|
|
|
|
Comments
|
|
^^^^^^^^
|
|
|
|
``;`` or ``#`` ASCII character at the beginning of a line
|
|
indicates a comment. Comment lines are ignored.
|
|
|
|
Code examples
|
|
^^^^^^^^^^^^^
|
|
|
|
1. Suppressing change reports about types.
|
|
|
|
Suppose we have a library named ``libtest1-v0.so`` which
|
|
contains this very useful code: ::
|
|
|
|
$ cat -n test1-v0.cc
|
|
1 // A forward declaration for a type considered to be opaque to
|
|
2 // function foo() below.
|
|
3 struct opaque_type;
|
|
4
|
|
5 // This function cannot touch any member of opaque_type. Hence,
|
|
6 // changes to members of opaque_type should not impact foo, as far as
|
|
7 // ABI is concerned.
|
|
8 void
|
|
9 foo(opaque_type*)
|
|
10 {
|
|
11 }
|
|
12
|
|
13 struct opaque_type
|
|
14 {
|
|
15 int member0;
|
|
16 char member1;
|
|
17 };
|
|
$
|
|
|
|
Let's change the layout of struct opaque_type by inserting a data
|
|
member around line 15, leading to a new version of the library,
|
|
that we shall name ``libtest1-v1.so``: ::
|
|
|
|
$ cat -n test1-v1.cc
|
|
1 // A forward declaration for a type considered to be opaque to
|
|
2 // function foo() below.
|
|
3 struct opaque_type;
|
|
4
|
|
5 // This function cannot touch any member of opaque_type; Hence,
|
|
6 // changes to members of opaque_type should not impact foo, as far as
|
|
7 // ABI is concerned.
|
|
8 void
|
|
9 foo(opaque_type*)
|
|
10 {
|
|
11 }
|
|
12
|
|
13 struct opaque_type
|
|
14 {
|
|
15 char added_member; // <-- a new member got added here now.
|
|
16 int member0;
|
|
17 char member1;
|
|
18 };
|
|
$
|
|
|
|
Let's compile both examples. We shall not forget to compile them
|
|
with debug information generation turned on: ::
|
|
|
|
$ g++ -shared -g -Wall -o libtest1-v0.so test1-v0.cc
|
|
$ g++ -shared -g -Wall -o libtest1-v1.so test1-v1.cc
|
|
|
|
Let's ask :ref:`abidiff <abidiff_label>` which ABI differences it sees
|
|
between ``libtest1-v0.so`` and ``libtest1-v1.so``: ::
|
|
|
|
$ abidiff libtest1-v0.so libtest1-v1.so
|
|
Functions changes summary: 0 Removed, 1 Changed, 0 Added function
|
|
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
|
|
|
|
1 function with some indirect sub-type change:
|
|
|
|
[C]'function void foo(opaque_type*)' has some indirect sub-type changes:
|
|
parameter 0 of type 'opaque_type*' has sub-type changes:
|
|
in pointed to type 'struct opaque_type':
|
|
size changed from 64 to 96 bits
|
|
1 data member insertion:
|
|
'char opaque_type::added_member', at offset 0 (in bits)
|
|
2 data member changes:
|
|
'int opaque_type::member0' offset changed from 0 to 32
|
|
'char opaque_type::member1' offset changed from 32 to 64
|
|
|
|
|
|
So ``abidiff`` reports that the opaque_type's layout has changed
|
|
in a significant way, as far as ABI implications are concerned, in
|
|
theory. After all, a sub-type (``struct opaque_type``) of an
|
|
exported function (``foo()``) has seen its layout change. This
|
|
might have non negligible ABI implications. But in practice here,
|
|
the programmer of the litest1-v1.so library knows that the "soft"
|
|
contract between the function ``foo()`` and the type ``struct
|
|
opaque_type`` is to stay away from the data members of the type.
|
|
So layout changes of ``struct opaque_type`` should not impact
|
|
``foo()``.
|
|
|
|
Now to teach ``abidiff`` about this soft contract and have it
|
|
avoid emitting what amounts to false positives in this case, we
|
|
write the suppression specification file below: ::
|
|
|
|
$ cat test1.suppr
|
|
[suppress_type]
|
|
type_kind = struct
|
|
name = opaque_type
|
|
|
|
Translated in plain English, this suppression specification would
|
|
read: "Do not emit change reports about a struct which name is
|
|
opaque_type".
|
|
|
|
Let's now invoke ``abidiff`` on the two versions of the library
|
|
again, but this time with the suppression specification: ::
|
|
|
|
$ abidiff --suppressions test1.suppr libtest1-v0.so libtest1-v1.so
|
|
Functions changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added function
|
|
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
|
|
|
|
As you can see, ``abidiff`` does not report the change anymore; it
|
|
tells us that it was filtered out instead.
|
|
|
|
Suppressing change reports about types with data member
|
|
insertions
|
|
|
|
Suppose the first version of a library named ``libtest3-v0.so``
|
|
has this source code: ::
|
|
|
|
/* Compile this with:
|
|
gcc -g -Wall -shared -o libtest3-v0.so test3-v0.c
|
|
*/
|
|
|
|
struct S
|
|
{
|
|
char member0;
|
|
int member1; /*
|
|
between member1 and member2, there is some padding,
|
|
at least on some popular platforms. On
|
|
these platforms, adding a small enough data
|
|
member into that padding shouldn't change
|
|
the offset of member1. Right?
|
|
*/
|
|
};
|
|
|
|
int
|
|
foo(struct S* s)
|
|
{
|
|
return s->member0 + s->member1;
|
|
}
|
|
|
|
Now, suppose the second version of the library named
|
|
``libtest3-v1.so`` has this source code in which a data member
|
|
has been added in the padding space of struct S and another data
|
|
member has been added at its end: ::
|
|
|
|
/* Compile this with:
|
|
gcc -g -Wall -shared -o libtest3-v1.so test3-v1.c
|
|
*/
|
|
|
|
struct S
|
|
{
|
|
char member0;
|
|
char inserted1; /* <---- A data member has been added here... */
|
|
int member1;
|
|
char inserted2; /* <---- ... and another one has been added here. */
|
|
};
|
|
|
|
int
|
|
foo(struct S* s)
|
|
{
|
|
return s->member0 + s->member1;
|
|
}
|
|
|
|
|
|
In libtest3-v1.so, adding char data members ``S::inserted1`` and
|
|
``S::inserted2`` can be considered harmless (from an ABI compatibility
|
|
perspective), at least on the x86 platform, because that doesn't
|
|
change the offsets of the data members S::member0 and S::member1. But
|
|
then running ``abidiff`` on these two versions of library yields: ::
|
|
|
|
$ abidiff libtest3-v0.so libtest3-v1.so
|
|
Functions changes summary: 0 Removed, 1 Changed, 0 Added function
|
|
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
|
|
|
|
1 function with some indirect sub-type change:
|
|
|
|
[C]'function int foo(S*)' has some indirect sub-type changes:
|
|
parameter 0 of type 'S*' has sub-type changes:
|
|
in pointed to type 'struct S':
|
|
type size changed from 64 to 96 bits
|
|
2 data member insertions:
|
|
'char S::inserted1', at offset 8 (in bits)
|
|
'char S::inserted2', at offset 64 (in bits)
|
|
$
|
|
|
|
|
|
|
|
That is, ``abidiff`` shows us the two changes, even though we (the
|
|
developers of that very involved library) know that these changes
|
|
are harmless in this particular context.
|
|
|
|
Luckily, we can devise a suppression specification that essentially
|
|
tells abidiff to filter out change reports about adding a data
|
|
member between ``S::member0`` and ``S::member1``, and adding a data
|
|
member at the end of struct S. We have written such a suppression
|
|
specification in a file called test3-1.suppr and it unsurprisingly
|
|
looks like: ::
|
|
|
|
[suppress_type]
|
|
name = S
|
|
has_data_member_inserted_between = {offset_after(member0), offset_of(member1)}
|
|
has_data_member_inserted_at = end
|
|
|
|
|
|
Now running ``abidiff`` with this suppression specification yields: ::
|
|
|
|
$ ../build/tools/abidiff --suppressions test3-1.suppr libtest3-v0.so libtest3-v1.so
|
|
Functions changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added function
|
|
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
|
|
|
|
$
|
|
|
|
|
|
Hooora! \\o/ (I guess)
|
|
|
|
.. _example_accessed_through_label:
|
|
|
|
Suppressing change reports about types accessed either directly
|
|
or through pointers
|
|
|
|
Suppose we have a first version of an object file which source
|
|
code is the file widget-v0.cc below: ::
|
|
|
|
// Compile with: g++ -g -c widget-v0.cc
|
|
|
|
struct widget
|
|
{
|
|
int x;
|
|
int y;
|
|
|
|
widget()
|
|
:x(), y()
|
|
{}
|
|
};
|
|
|
|
void
|
|
fun0(widget*)
|
|
{
|
|
// .. do stuff here.
|
|
}
|
|
|
|
void
|
|
fun1(widget&)
|
|
{
|
|
// .. do stuff here ..
|
|
}
|
|
|
|
void
|
|
fun2(widget w)
|
|
{
|
|
// ... do other stuff here ...
|
|
}
|
|
|
|
Now suppose in the second version of that file, named
|
|
widget-v1.cc, we have added some data members at the end of
|
|
the type ``struct widget``; here is what the content of that file
|
|
would look like: ::
|
|
|
|
// Compile with: g++ -g -c widget-v1.cc
|
|
|
|
struct widget
|
|
{
|
|
int x;
|
|
int y;
|
|
int w; // We have added these two new data members here ..
|
|
int h; // ... and here.
|
|
|
|
widget()
|
|
: x(), y(), w(), h()
|
|
{}
|
|
};
|
|
|
|
void
|
|
fun0(widget*)
|
|
{
|
|
// .. do stuff here.
|
|
}
|
|
|
|
void
|
|
fun1(widget&)
|
|
{
|
|
// .. do stuff here ..
|
|
}
|
|
|
|
void
|
|
fun2(widget w)
|
|
{
|
|
// ... do other stuff here ...
|
|
}
|
|
|
|
When we invoke ``abidiff`` on the object files resulting from the
|
|
compilation of the two file above, here is what we get: ::
|
|
|
|
$ abidiff widget-v0.o widget-v1.o
|
|
Functions changes summary: 0 Removed, 2 Changed (1 filtered out), 0 Added functions
|
|
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
|
|
|
|
2 functions with some indirect sub-type change:
|
|
|
|
[C]'function void fun0(widget*)' has some indirect sub-type changes:
|
|
parameter 1 of type 'widget*' has sub-type changes:
|
|
in pointed to type 'struct widget':
|
|
type size changed from 64 to 128 bits
|
|
2 data member insertions:
|
|
'int widget::w', at offset 64 (in bits)
|
|
'int widget::h', at offset 96 (in bits)
|
|
|
|
[C]'function void fun2(widget)' has some indirect sub-type changes:
|
|
parameter 1 of type 'struct widget' has sub-type changes:
|
|
details were reported earlier
|
|
$
|
|
|
|
I guess a little bit of explaining is due here. ``abidiff``
|
|
detects that two data member got added at the end of ``struct
|
|
widget``. it also tells us that the type change impacts the
|
|
exported function ``fun0()`` which uses the type ``struct
|
|
widget`` through a pointer, in its signature.
|
|
|
|
Careful readers will notice that the change to ``struct widget``
|
|
also impacts the exported function ``fun1()``, that uses type
|
|
``struct widget`` through a reference. But then ``abidiff``
|
|
doesn't tell us about the impact on that function ``fun1()``
|
|
because it has evaluated that change as being **redundant** with
|
|
the change it reported on ``fun0()``. It has thus filtered it
|
|
out, to avoid cluttering the output with noise.
|
|
|
|
Redundancy detection and filtering is fine and helpful to avoid
|
|
burying the important information in a sea of noise. However, it
|
|
must be treated with care, by fear of mistakenly filtering out
|
|
relevant and important information.
|
|
|
|
That is why ``abidiff`` tells us about the impact that the change
|
|
to ``struct widget`` has on function ``fun2()``. In this case,
|
|
that function uses the type ``struct widget`` **directly** (in
|
|
its signature). It does not use it via a pointer or a reference.
|
|
In this case, the direct use of this type causes ``fun2()`` to be
|
|
exposed to a potentially harmful ABI change. Hence, the report
|
|
about ``fun2()`` is not filtered out, even though it's about that
|
|
same change on ``struct widget``.
|
|
|
|
To go further in suppressing reports about changes that are
|
|
harmless and keeping only those that we know are harmful, we
|
|
would like to go tell abidiff to suppress reports about this
|
|
particular ``struct widget`` change when it impacts uses of
|
|
``struct widget`` through a pointer or reference. In other
|
|
words, suppress the change reports about ``fun0()`` **and**
|
|
``fun1()``. We would then write this suppression specification,
|
|
in file ``widget.suppr``: ::
|
|
|
|
[suppress_type]
|
|
name = widget
|
|
type_kind = struct
|
|
has_data_member_inserted_at = end
|
|
accessed_through = reference-or-pointer
|
|
|
|
# So this suppression specification says to suppress reports about
|
|
# the type 'struct widget', if this type was added some data member
|
|
# at its end, and if the change impacts uses of the type through a
|
|
# reference or a pointer.
|
|
|
|
Invoking ``abidiff`` on ``widget-v0.o`` and ``widget-v1.o`` with
|
|
this suppression specification yields: ::
|
|
|
|
$ abidiff --suppressions widget.suppr widget-v0.o widget-v1.o
|
|
Functions changes summary: 0 Removed, 1 Changed (2 filtered out), 0 Added function
|
|
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
|
|
|
|
1 function with some indirect sub-type change:
|
|
|
|
[C]'function void fun2(widget)' has some indirect sub-type changes:
|
|
parameter 1 of type 'struct widget' has sub-type changes:
|
|
type size changed from 64 to 128 bits
|
|
2 data member insertions:
|
|
'int widget::w', at offset 64 (in bits)
|
|
'int widget::h', at offset 96 (in bits)
|
|
$
|
|
|
|
As expected, I guess.
|
|
|
|
Suppressing change reports about functions.
|
|
|
|
Suppose we have a first version a library named
|
|
``libtest2-v0.so`` whose source code is: ::
|
|
|
|
$ cat -n test2-v0.cc
|
|
|
|
1 struct S1
|
|
2 {
|
|
3 int m0;
|
|
4
|
|
5 S1()
|
|
6 : m0()
|
|
7 {}
|
|
8 };
|
|
9
|
|
10 struct S2
|
|
11 {
|
|
12 int m0;
|
|
13
|
|
14 S2()
|
|
15 : m0()
|
|
16 {}
|
|
17 };
|
|
18
|
|
19 struct S3
|
|
20 {
|
|
21 int m0;
|
|
22
|
|
23 S3()
|
|
24 : m0()
|
|
25 {}
|
|
26 };
|
|
27
|
|
28 int
|
|
29 func(S1&)
|
|
30 {
|
|
31 // suppose the code does something with the argument.
|
|
32 return 0;
|
|
33
|
|
34 }
|
|
35
|
|
36 char
|
|
37 func(S2*)
|
|
38 {
|
|
39 // suppose the code does something with the argument.
|
|
40 return 0;
|
|
41 }
|
|
42
|
|
43 unsigned
|
|
44 func(S3)
|
|
45 {
|
|
46 // suppose the code does something with the argument.
|
|
47 return 0;
|
|
48 }
|
|
$
|
|
|
|
And then we come up with a second version ``libtest2-v1.so`` of
|
|
that library; the source code is modified by making the
|
|
structures ``S1``, ``S2``, ``S3`` inherit another struct: ::
|
|
|
|
$ cat -n test2-v1.cc
|
|
1 struct base_type
|
|
2 {
|
|
3 int m_inserted;
|
|
4 };
|
|
5
|
|
6 struct S1 : public base_type // <--- S1 now has base_type as its base
|
|
7 // type.
|
|
8 {
|
|
9 int m0;
|
|
10
|
|
11 S1()
|
|
12 : m0()
|
|
13 {}
|
|
14 };
|
|
15
|
|
16 struct S2 : public base_type // <--- S2 now has base_type as its base
|
|
17 // type.
|
|
18 {
|
|
19 int m0;
|
|
20
|
|
21 S2()
|
|
22 : m0()
|
|
23 {}
|
|
24 };
|
|
25
|
|
26 struct S3 : public base_type // <--- S3 now has base_type as its base
|
|
27 // type.
|
|
28 {
|
|
29 int m0;
|
|
30
|
|
31 S3()
|
|
32 : m0()
|
|
33 {}
|
|
34 };
|
|
35
|
|
36 int
|
|
37 func(S1&)
|
|
38 {
|
|
39 // suppose the code does something with the argument.
|
|
40 return 0;
|
|
41
|
|
42 }
|
|
43
|
|
44 char
|
|
45 func(S2*)
|
|
46 {
|
|
47 // suppose the code does something with the argument.
|
|
48 return 0;
|
|
49 }
|
|
50
|
|
51 unsigned
|
|
52 func(S3)
|
|
53 {
|
|
54 // suppose the code does something with the argument.
|
|
55 return 0;
|
|
56 }
|
|
$
|
|
|
|
Now let's build the two libraries: ::
|
|
|
|
g++ -Wall -g -shared -o libtest2-v0.so test2-v0.cc
|
|
g++ -Wall -g -shared -o libtest2-v0.so test2-v0.cc
|
|
|
|
Let's look at the output of ``abidiff``: ::
|
|
|
|
$ abidiff libtest2-v0.so libtest2-v1.so
|
|
Functions changes summary: 0 Removed, 3 Changed, 0 Added functions
|
|
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
|
|
|
|
3 functions with some indirect sub-type change:
|
|
|
|
[C]'function unsigned int func(S3)' has some indirect sub-type changes:
|
|
parameter 0 of type 'struct S3' has sub-type changes:
|
|
size changed from 32 to 64 bits
|
|
1 base class insertion:
|
|
struct base_type
|
|
1 data member change:
|
|
'int S3::m0' offset changed from 0 to 32
|
|
|
|
[C]'function char func(S2*)' has some indirect sub-type changes:
|
|
parameter 0 of type 'S2*' has sub-type changes:
|
|
in pointed to type 'struct S2':
|
|
size changed from 32 to 64 bits
|
|
1 base class insertion:
|
|
struct base_type
|
|
1 data member change:
|
|
'int S2::m0' offset changed from 0 to 32
|
|
|
|
[C]'function int func(S1&)' has some indirect sub-type changes:
|
|
parameter 0 of type 'S1&' has sub-type changes:
|
|
in referenced type 'struct S1':
|
|
size changed from 32 to 64 bits
|
|
1 base class insertion:
|
|
struct base_type
|
|
1 data member change:
|
|
'int S1::m0' offset changed from 0 to 32
|
|
$
|
|
|
|
Let's tell ``abidiff`` to avoid showing us the differences on the
|
|
overloads of ``func`` that takes either a pointer or a reference.
|
|
For that, we author this simple suppression specification: ::
|
|
|
|
$ cat -n libtest2.suppr
|
|
1 [suppress_function]
|
|
2 name = func
|
|
3 parameter = '0 S1&
|
|
4
|
|
5 [suppress_function]
|
|
6 name = func
|
|
7 parameter = '0 S2*
|
|
$
|
|
|
|
And then let's invoke ``abidiff`` with the suppression
|
|
specification: ::
|
|
|
|
$ ../build/tools/abidiff --suppressions libtest2.suppr libtest2-v0.so libtest2-v1.so
|
|
Functions changes summary: 0 Removed, 1 Changed (2 filtered out), 0 Added function
|
|
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
|
|
|
|
1 function with some indirect sub-type change:
|
|
|
|
[C]'function unsigned int func(S3)' has some indirect sub-type changes:
|
|
parameter 0 of type 'struct S3' has sub-type changes:
|
|
size changed from 32 to 64 bits
|
|
1 base class insertion:
|
|
struct base_type
|
|
1 data member change:
|
|
'int S3::m0' offset changed from 0 to 32
|
|
|
|
|
|
The suppression specification could be reduced using
|
|
:ref:`regular expressions <suppr_regexp_label>`: ::
|
|
|
|
$ cat -n libtest2-1.suppr
|
|
1 [suppress_function]
|
|
2 name = func
|
|
3 parameter = '0 /^S.(&|\\*)/
|
|
$
|
|
|
|
$ ../build/tools/abidiff --suppressions libtest2-1.suppr libtest2-v0.so libtest2-v1.so
|
|
Functions changes summary: 0 Removed, 1 Changed (2 filtered out), 0 Added function
|
|
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
|
|
|
|
1 function with some indirect sub-type change:
|
|
|
|
[C]'function unsigned int func(S3)' has some indirect sub-type changes:
|
|
parameter 0 of type 'struct S3' has sub-type changes:
|
|
size changed from 32 to 64 bits
|
|
1 base class insertion:
|
|
struct base_type
|
|
1 data member change:
|
|
'int S3::m0' offset changed from 0 to 32
|
|
|
|
$
|
|
|
|
.. _ELF: http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
|
|
|
|
.. _Ini File Syntax: http://en.wikipedia.org/wiki/INI_file
|
|
|
|
.. _GNU C Library: http://www.gnu.org/software/libc
|