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_data_member_offset_selector_expressions_label:
+
+ - data member offset selector expressions, such as:
+
+ - 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``.
+
+ - the function call expression
+ ``offset_of_first_data_member_regexp(data-member-name-regexp)``
+ where `data-member-name-regexp` is a regular expression
+ matching a data member. The value of this function
+ call expression is an integer that represents the
+ offset of the first data member which name matches the
+ regular expression argument. If no data member of a
+ given class type matches the regular expression, then
+ the class type won't match the current directive.
+
+ - the function call expression
+ ``offset_of_last_data_member_regexp(data-member-name-regexp)``
+ where `data-member-name-regexp` is a regular expression
+ matching a data member. The value of this function
+ call expression is an integer that represents the
+ offset of the last data member which name matches the
+ regular expression argument. If no data member of a
+ given class type matches the regular expression, then
+ the class type won't match the current directive.
.. _suppr_has_data_member_inserted_between_label:
#include <stdint.h>
#include <cstddef>
#include <cstdlib>
+#include <regex.h>
#include <list>
#include <memory>
#include <ostream>
// 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
{
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;
#include <unordered_set>
#include "abg-ini.h"
-#include "abg-comparison.h"
+#include "abg-ir.h"
namespace abigail
{
/// 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.
///
#include "config.h"
#include <fcntl.h> /* For open(3) */
+#include <sstream>
#include <iostream>
#include <memory>
#include <map>
#include <unistd.h>
#include <limits.h>
#include <elfutils/libdwfl.h>
+#include <sstream>
#include "abg-elf-helpers.h"
#include "abg-tools-utils.h"
#include "abg-interned-str.h"
#include "abg-ir.h"
#include "abg-corpus.h"
+#include "abg-regex.h"
ABG_END_EXPORT_DECLARATIONS
// </headers defining libabigail's API>
return o.str();
}
+/// Find the first data member of a class or union which name matches
+/// a regular expression.
+///
+/// @param t the class or union to consider.
+///
+/// @param r the regular expression to consider.
+///
+/// @return the data member matched by @p r or nil if none was found.
+var_decl_sptr
+find_first_data_member_matching_regexp(const class_or_union& t,
+ const regex::regex_t_sptr& r)
+{
+ for (auto data_member : t.get_data_members())
+ {
+ if (regex::match(r, data_member->get_name()))
+ return data_member;
+ }
+
+ return var_decl_sptr();
+}
+
+/// Find the last data member of a class or union which name matches
+/// a regular expression.
+///
+/// @param t the class or union to consider.
+///
+/// @param r the regular expression to consider.
+///
+/// @return the data member matched by @p r or nil if none was found.
+var_decl_sptr
+find_last_data_member_matching_regexp(const class_or_union& t,
+ const regex::regex_t_sptr& regex)
+{
+ auto d = t.get_data_members().rbegin();
+ auto e = t.get_data_members().rend();
+ for (; d != e; ++d)
+ {
+ if (regex::match(regex, (*d)->get_name()))
+ return *d;
+ }
+
+ return var_decl_sptr();
+}
+
bool
ir_traversable_base::traverse(ir_node_visitor&)
{return true;}
#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>
namespace suppr
{
+// Inject the abigail::comparison namespace in here.
+using namespace comparison;
+
using std::dynamic_pointer_cast;
using regex::regex_t_sptr;
{
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")
+ || 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;
}
}
test-diff-suppr/test-has-data-member-v0.o \
test-diff-suppr/test-has-data-member-v1.cc \
test-diff-suppr/test-has-data-member-v1.o \
+test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt \
+test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt \
+test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt \
+test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt \
+test-diff-suppr/test-has-data-member-inserted-between-1-v0.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v0.o \
+test-diff-suppr/test-has-data-member-inserted-between-1-v1.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v1.o \
+test-diff-suppr/test-has-data-member-inserted-between-1-v2.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v2.o \
+test-diff-suppr/test-has-data-member-inserted-between-1-v3.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v3.o \
+test-diff-suppr/test-has-data-member-inserted-between-1-v4.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v4.o \
+test-diff-suppr/test-has-data-member-inserted-between-1.suppr \
\
test-diff-dwarf-abixml/test0-pr19026-libvtkIOSQL-6.1.so.1 \
test-diff-dwarf-abixml/test0-pr19026-libvtkIOSQL-6.1.so.1.abi \
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added variable
+
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 1 Changed, 0 Added variable
+
+1 Changed variable:
+
+ [C] 'S s' was changed at test-has-data-member-inserted-between-1-v2.c:11:1:
+ type of variable changed:
+ type size hasn't changed
+ 1 data member insertion:
+ 'char data_member_incorrectly_inserted', at offset 32 (in bits) at test-has-data-member-inserted-between-1-v2.c:4:1
+ 1 data member change:
+ 'char member1' offset changed from 32 to 40 (in bits) (by +8 bits)
+
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 1 Changed, 0 Added variable
+
+1 Changed variable:
+
+ [C] 'S s' was changed at test-has-data-member-inserted-between-1-v3.c:11:1:
+ size of symbol changed from 20 to 24
+ type of variable changed:
+ type size changed from 160 to 192 (in bits)
+ 1 data member insertion:
+ 'char data_member_incorrectly_inserted', at offset 160 (in bits) at test-has-data-member-inserted-between-1-v3.c:8:1
+
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 1 Changed, 0 Added variable
+
+1 Changed variable:
+
+ [C] 'S s' was changed at test-has-data-member-inserted-between-1-v4.c:10:1:
+ type of variable changed:
+ type size hasn't changed
+ 1 data member insertion:
+ 'char data_member_incorrectly_inserted', at offset 40 (in bits) at test-has-data-member-inserted-between-1-v4.c:5:1
+
--- /dev/null
+struct S
+{
+ int member0;
+ char member1;
+ unsigned __special_padding_space1;
+ unsigned __special_padding_space2;
+ unsigned __special_padding_space3;
+};
+
+struct S s;
--- /dev/null
+struct S
+{
+ int member0;
+ char member1;
+ int correctly_inserted_data_member;
+ unsigned __special_padding_space2;
+ unsigned __special_padding_space3;
+};
+
+struct S s;
--- /dev/null
+struct S
+{
+ int member0;
+ char data_member_incorrectly_inserted;
+ char member1;
+ unsigned __special_padding_space1;
+ unsigned __special_padding_space2;
+ unsigned __special_padding_space3;
+};
+
+struct S s;
--- /dev/null
+struct S
+{
+ int member0;
+ char member1;
+ unsigned __special_padding_space1;
+ unsigned __special_padding_space2;
+ unsigned __special_padding_space3;
+ char data_member_incorrectly_inserted;
+};
+
+struct S s;
--- /dev/null
+struct S
+{
+ int member0;
+ char member1;
+ char data_member_incorrectly_inserted;
+ unsigned __special_padding_space1;
+ unsigned __special_padding_space2;
+ unsigned __special_padding_space3;
+};
+struct S s;
--- /dev/null
+[suppress_type]
+ type_kind = struct
+ has_data_member_inserted_between =
+ {
+ offset_of_first_data_member_regexp(^__special_padding_space),
+ offset_of_last_data_member_regexp(^__special_padding_space)
+ }
"data/test-diff-suppr/test-has-data-member-output-2.txt",
"output/test-diff-suppr/test-has-data-member-output-2.4.txt"
},
- {
+ {
"data/test-diff-suppr/test-has-data-member-v0.o",
"data/test-diff-suppr/test-has-data-member-v1.o",
"",
"data/test-diff-suppr/test-has-data-member-output-1.txt",
"output/test-diff-suppr/test-has-data-member-output-1.4.txt"
},
+ {
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o",
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.o",
+ "",
+ "",
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr",
+ "--drop-private-types --no-default-suppression",
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt",
+ "output/test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt"
+ },
+ {
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o",
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.o",
+ "",
+ "",
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr",
+ "--drop-private-types --no-default-suppression",
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt",
+ "output/test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt"
+ },
+ {
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o",
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.o",
+ "",
+ "",
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr",
+ "--drop-private-types --no-default-suppression",
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt",
+ "output/test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt"
+ },
+ {
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o",
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.o",
+ "",
+ "",
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr",
+ "--drop-private-types --no-default-suppression",
+ "data/test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt",
+ "output/test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt"
+ },
// This should be the last entry
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
};