libabigail
Loading...
Searching...
No Matches
abg-suppression.cc
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2// -*- Mode: C++ -*-
3//
4// Copyright (C) 2016-2025 Red Hat, Inc.
5//
6// Author: Dodji Seketeli
7
8/// @file
9///
10/// This contains the implementation of the suppression engine of
11/// libabigail.
12
13#include <algorithm>
14
15#include "abg-internal.h"
16#include <memory>
17#include <limits>
18
19// <headers defining libabigail's API go under here>
20ABG_BEGIN_EXPORT_DECLARATIONS
21
22#include "abg-ini.h"
23#include "abg-comp-filter.h"
24#include "abg-suppression.h"
25#include "abg-tools-utils.h"
26#include "abg-fe-iface.h"
27#include "abg-comparison.h"
28
29ABG_END_EXPORT_DECLARATIONS
30// </headers defining libabigail's API>
31
33
34namespace abigail
35{
36
37namespace suppr
38{
39
40// Inject the abigail::comparison namespace in here.
41using namespace comparison;
42
43using std::dynamic_pointer_cast;
45
46/// @return the string constant "offset_of_flexible_array_data_member".
47static const string&
48OFFSET_OF_FLEXIBLE_ARRAY_DATA_MEMBER_STRING()
49{
50 static string s = "offset_of_flexible_array_data_member";
51 return s;
52}
53
54/// @return the string constant "end";
55static const string&
56END_STRING()
57{
58 static string s = "end";
59 return s;
60}
61
62// <parsing stuff>
63
64// section parsing
65
66/// Check if a section has at least one of the given properties.
67///
68/// @param names pointer to the start of an array of names.
69///
70/// @param count number of names in the array.
71///
72/// @return whether at least of one the properties was found.
73bool
74check_sufficient_props(const char *const * names, size_t count,
75 const ini::config::section& section)
76{
77 for (const char *const * name = names; name < names + count; ++name)
78 if (section.find_property(*name))
79 return true;
80 // TODO: Possibly give reason for failure in a message here.
81 return false;
82}
83
84// </parsing stuff>
85
86// <suppression_base stuff>
87
88/// Constructor for @ref suppression_base
89///
90/// @param a label for the suppression. This represents just a
91/// comment.
92suppression_base::suppression_base(const string& label)
93 : priv_(new priv(label))
94{}
95
96/// Constructor for @ref suppression_base
97///
98/// @param a label for the suppression. This represents just a
99/// comment.
100///
101/// @param file_name_regex_str the regular expression that denotes the
102/// file name to match.
103///
104/// @param file_name_not_regex_str the regular expression that denotes
105/// the file name to *NOT* match.
106suppression_base::suppression_base(const string& label,
107 const string& file_name_regex_str,
108 const string& file_name_not_regex_str)
109 : priv_(new priv(label,
110 file_name_regex_str,
111 file_name_not_regex_str))
112{
113}
114
115/// Tests if the current suppression specification is to avoid adding
116/// the matched ABI artifact to the internal representation or not.
117///
118/// @return true iff the current suppression specification is to avoid
119/// adding the matched ABI artifact to the internal representation.
120bool
122{return priv_->drops_artifact_;}
123
124/// Set the flag that says whether the current suppression
125/// specification is to avoid adding the matched ABI artifact to the
126/// internal representation or not.
127///
128/// @param f the flag to set to true iff the current suppression
129/// specification is to avoid adding the matched ABI artifact to the
130/// internal representation.
131void
133{priv_->drops_artifact_ = f;}
134
135/// Test is the suppression specification is artificial.
136///
137/// Artificial means that the suppression was automatically generated
138/// by libabigail, rather than being constructed from a suppression
139/// file provided by the user.
140///
141/// @return TRUE iff the suppression specification is artificial.
142bool
144{return priv_->is_artificial_;}
145
146/// Set a flag saying if the suppression specification is artificial
147/// or not.
148///
149/// Artificial means that the suppression was automatically generated
150/// by libabigail, rather than being constructed from a suppression
151/// file provided by the user.
152void
154{priv_->is_artificial_ = f;}
155
156/// Getter for the label associated to this suppression specification.
157///
158/// @return the label.
159const string
161{return priv_->label_;}
162
163/// Setter for the label associated to this suppression specification.
164///
165/// @param label the new label.
166void
167suppression_base::set_label(const string& label)
168{priv_->label_ = label;}
169
170/// Setter for the "file_name_regex" property of the current instance
171/// of @ref suppression_base.
172///
173/// The "file_name_regex" property is a regular expression string that
174/// designates the file name that contains the ABI artifact this
175/// suppression should apply to.
176///
177/// @param regexp the new regular expression string.
178void
180{priv_->file_name_regex_str_ = regexp;}
181
182/// Getter for the "file_name_regex" property of the current instance
183/// of @ref suppression_base.
184///
185/// The "file_name_regex" property is a regular expression string that
186/// designates the file name that contains the ABI artifacts this
187/// suppression should apply to.
188///
189/// @return the regular expression string.
190const string&
192{return priv_->file_name_regex_str_;}
193
194/// Setter for the "file_name_not_regex" property of the current
195/// instance of @ref suppression_base.
196///
197/// The current suppression specification should apply to ABI
198/// artifacts of a file which name does *NOT* match the regular
199/// expression string designated by the "file_name_not_regex"
200/// property.
201///
202/// @param regexp the new regular expression string.
203void
205{priv_->file_name_not_regex_str_ = regexp;}
206
207/// Getter for the "file_name_not_regex" property of the current
208/// instance of @ref suppression_base.
209///
210/// The current suppression specification should apply to ABI
211/// artifacts of a file which name does *NOT* match the regular
212/// expression string designated by the "file_name_not_regex"
213/// property.
214///
215/// @return the regular expression string.
216const string&
218{return priv_->file_name_not_regex_str_;}
219
220/// Test if the current suppression has a property related to file
221/// name.
222///
223/// @return true iff the current suppression has either a
224/// file_name_regex or a file_name_not_regex property.
225bool
231
232/// Setter of the "soname_regex_str property of the current instance
233/// of @ref suppression_base.
234///
235/// The "soname_regex_str" is a regular expression string that
236/// designates the soname of the shared library that contains the ABI
237/// artifacts this suppression should apply to.
238///
239/// @param regexp the new regular expression string.
240void
242{priv_->soname_regex_str_ = regexp;}
243
244/// Getter of the "soname_regex_str property of the current instance
245/// of @ref suppression_base.
246///
247/// The "soname_regex_str" is a regular expression string that
248/// designates the soname of the shared library that contains the ABI
249/// artifacts this suppression should apply to.
250///
251/// @return the regular expression string.
252const string&
254{return priv_->soname_regex_str_;}
255
256/// Setter of the "soname_not_regex_str property of the current
257/// instance of @ref suppression_base.
258///
259/// The current suppression specification should apply to ABI
260/// artifacts of a shared library which SONAME does *NOT* match the
261/// regular expression string designated by the "soname_not_regex"
262/// property.
263///
264/// @param regexp the new regular expression string.
265void
267{priv_->soname_not_regex_str_ = regexp;}
268
269/// Getter of the "soname_not_regex_str property of the current
270/// instance of @ref suppression_base.
271///
272/// The current suppression specification should apply to ABI
273/// artifacts of a shared library which SONAME does *NOT* match the
274/// regular expression string designated by the "soname_not_regex"
275/// property.
276///
277/// @return the regular expression string.
278const string&
280{return priv_->soname_not_regex_str_;}
281
282/// Test if the current suppression has a property related to SONAMEs.
283///
284/// @return true iff the current suppression has either a soname_regex
285/// or a soname_not_regex property.
286bool
288{
289 return (!(get_soname_regex_str().empty()
290 && get_soname_not_regex_str().empty()));
291}
292
293/// Constructor of the @ref negated_suppression_base.
297
298/// Destructor of the @ref negated_suppression_base.
302
303/// Test if a suppression specification is a negated suppression.
304///
305/// @param s the suppression to consider.
306///
307/// @return true iff @p s is an instance of @ref
308/// negated_suppression_base.
309bool
311{
312 bool result = true;
313 try
314 {
315 if (const negated_suppression_base* s_prime =
316 &dynamic_cast<const negated_suppression_base&>(s))
317 return !!s_prime;
318 }
319 catch (...)
320 {
321 result = false;
322 }
323 return result;
324}
325
326/// Test if a suppression specification is a negated suppression.
327///
328/// @param s the suppression to consider.
329///
330/// @return true a pointer to the @ref negated_suppression_base which
331/// @p s, or nil if it's not a negated suppression.
332/// negated_suppression_base.
335{
336 const negated_suppression_base* result = nullptr;
337 result = dynamic_cast<const negated_suppression_base*>(s);
338 return result;
339}
340
341/// Test if a suppression specification is a negated suppression.
342///
343/// @param s the suppression to consider.
344///
345/// @return true a pointer to the @ref negated_suppression_base which
346/// @p s, or nil if it's not a negated suppression.
347/// negated_suppression_base.
350{
352 result = dynamic_pointer_cast<negated_suppression_base>(s);
353 return result;
354}
355
356/// Check if the SONAMEs of the two binaries being compared match the
357/// content of the properties "soname_regexp" and "soname_not_regexp"
358/// of the current suppression specification.
359///
360/// @param suppr the suppression specification
361///
362/// @param ctxt the context of the comparison.
363///
364/// @return false if the regular expression contained in the property
365/// soname_regexp or in the property "soname_not_regexp" does *NOT*
366/// match at least one of the SONAMEs of the two binaries being
367/// compared. Return true otherwise.
368static bool
369sonames_of_binaries_match(const suppression_base& suppr,
370 const diff_context& ctxt)
371{
372 // Check if the sonames of the binaries match
373 string first_soname = ctxt.get_corpus_diff()->first_corpus()->get_soname(),
374 second_soname = ctxt.get_corpus_diff()->second_corpus()->get_soname();
375
376 if (!suppr.has_soname_related_property())
377 return false;
378
379 if (!suppr.priv_->matches_soname(first_soname)
380 && !suppr.priv_->matches_soname(second_soname))
381 return false;
382
383 return true;
384}
385
386/// Check if the names of the two binaries being compared match the
387/// content of the properties "file_name_regexp" and
388/// "file_name_not_regexp".
389///
390/// @param suppr the current suppression specification.
391///
392/// @param ctxt the context of the comparison.
393///
394/// @return false if the regular expression contained in the property
395/// file_name_regexp or in the property "file_name_not_regexp" does
396/// *NOT* match at least one of the names of the two binaries being
397/// compared. Return true otherwise.
398static bool
399names_of_binaries_match(const suppression_base& suppr,
400 const diff_context &ctxt)
401{
402 // Check if the file names of the binaries match
403 string first_binary_path = ctxt.get_corpus_diff()->first_corpus()->get_path(),
404 second_binary_path = ctxt.get_corpus_diff()->second_corpus()->get_path();
405
406 if (!suppr.has_file_name_related_property())
407 return false;
408
409 if (!suppr.priv_->matches_binary_name(first_binary_path)
410 && !suppr.priv_->matches_binary_name(second_binary_path))
411 return false;
412
413 return true;
414}
415
416suppression_base::~suppression_base()
417{}
418
420read_type_suppression(const ini::config::section& section);
421
423read_function_suppression(const ini::config::section& section);
424
426read_variable_suppression(const ini::config::section& section);
427
429read_file_suppression(const ini::config::section& section);
430
431/// Read a vector of suppression specifications from the sections of
432/// an ini::config.
433///
434/// Note that this function needs to be updated each time a new kind
435/// of suppression specification is added.
436///
437/// @param config the config to read from.
438///
439/// @param suppressions out parameter. The vector of suppressions to
440/// append the newly read suppressions to.
441static void
442read_suppressions(const ini::config& config,
443 suppressions_type& suppressions)
444{
446 for (ini::config::sections_type::const_iterator i =
447 config.get_sections().begin();
448 i != config.get_sections().end();
449 ++i)
450 if ((s = read_type_suppression(**i))
451 || (s = read_function_suppression(**i))
452 || (s = read_variable_suppression(**i))
453 || (s = read_file_suppression(**i)))
454 suppressions.push_back(s);
455
456}
457
458/// Read suppressions specifications from an input stream.
459///
460/// @param input the input stream to read from.
461///
462/// @param suppressions the vector of suppressions to append the newly
463/// read suppressions to.
464void
465read_suppressions(std::istream& input,
466 suppressions_type& suppressions)
467{
469 read_suppressions(*config, suppressions);
470}
471
472/// Read suppressions specifications from an input file on disk.
473///
474/// @param input the path to the input file to read from.
475///
476/// @param suppressions the vector of suppressions to append the newly
477/// read suppressions to.
478void
479read_suppressions(const string& file_path,
480 suppressions_type& suppressions)
481{
483 read_suppressions(*config, suppressions);
484}
485// </suppression_base stuff>
486
487// <type_suppression stuff>
488
489/// Constructor for @ref type_suppression.
490///
491/// @param label the label of the suppression. This is just a free
492/// form comment explaining what the suppression is about.
493///
494/// @param type_name_regexp the regular expression describing the
495/// types about which diff reports should be suppressed. If it's an
496/// empty string, the parameter is ignored.
497///
498/// @param type_name the name of the type about which diff reports
499/// should be suppressed. If it's an empty string, the parameter is
500/// ignored.
501///
502/// Note that parameter @p type_name_regexp and @p type_name_regexp
503/// should not necessarily be populated. It usually is either one or
504/// the other that the user wants.
505type_suppression::type_suppression(const string& label,
506 const string& type_name_regexp,
507 const string& type_name)
508 : suppression_base(label),
509 priv_(new priv(type_name_regexp,
510 type_name,
511 /*consider_type_kind=*/false,
512 /*type_kind=*/CLASS_TYPE_KIND,
513 /*consider_reach_kind=*/false,
514 /*reach_kind=*/DIRECT_REACH_KIND))
515{}
516
517type_suppression::~type_suppression()
518{}
519
520/// Setter for the "type_name_regex" property of the type suppression
521/// specification.
522///
523/// This sets a regular expression that specifies the family of types
524/// about which diff reports should be suppressed.
525///
526/// @param name_regex_str the new regular expression to set.
527void
528type_suppression::set_type_name_regex_str(const string& name_regex_str)
529{priv_->type_name_regex_str_ = name_regex_str;}
530
531/// Getter for the "type_name_regex" property of the type suppression
532/// specification.
533///
534/// This returns a regular expression string that specifies the family
535/// of types about which diff reports should be suppressed.
536///
537/// @return the regular expression string.
538const string&
540{return priv_->type_name_regex_str_;}
541
542/// Setter for the "type_name_not_regex_str" property of the type
543/// suppression specification.
544///
545/// This returns a regular expression string that specifies the family
546/// of types that should be kept after suppression.
547///
548/// @param r the new regexp string.
549void
551{priv_->set_type_name_not_regex_str(r);}
552
553/// Getter for the "type_name_not_regex_str" property of the type
554/// suppression specification.
555///
556/// This returns a regular expression string that specifies the family
557/// of types that should be kept after suppression.
558///
559/// @return the new regexp string.
560const string&
562{return priv_->get_type_name_not_regex_str();}
563
564/// Setter for the name of the type about which diff reports should be
565/// suppressed.
566///
567/// @param name the new type name.
568void
570{priv_->type_name_ = name;}
571
572/// Getter for the name of the type about which diff reports should be
573/// suppressed.
574///
575/// @param return the type name.
576const string&
578{return priv_->type_name_;}
579
580/// Getter of the property that says whether to consider the kind of
581/// type this suppression is about.
582///
583/// @return the boolean value of the property.
584bool
586{return priv_->consider_type_kind_;}
587
588/// Setter of the property that says whether to consider the kind of
589/// type this suppression is about.
590///
591/// @param f the new boolean value of the property.
592void
594{priv_->consider_type_kind_ = f;}
595
596/// Setter of the kind of type this suppression is about.
597///
598/// Note that this will be considered during evaluation of the
599/// suppression only if type_suppression::get_consider_type_kind()
600/// returns true.
601///
602/// @param k the new kind of type this suppression is about.
603void
605{priv_->type_kind_ = k;}
606
607/// Getter of the kind of type this suppression is about.
608///
609/// Note that this will be considered during evaluation of the
610/// suppression only if type_suppression::get_consider_type_kind()
611/// returns true.
612///
613/// @return the kind of type this suppression is about.
616{return priv_->type_kind_;}
617
618/// Test if the current type suppression specification
619/// suggests to consider how the matching diff node is reached.
620///
621/// @return true if the current type suppression specification
622/// suggests to consider how the matching diff node is reached.
623bool
625{return priv_->consider_reach_kind_;}
626
627/// Set a flag saying if the current type suppression specification
628/// suggests to consider how the matching diff node is reached.
629///
630/// @param f the new value of the flag. It's true iff the current
631/// type suppression specification suggests to consider how the
632/// matching diff node is reached.
633void
635{priv_->consider_reach_kind_ = f;}
636
637/// Getter of the way the diff node matching the current suppression
638/// specification is to be reached.
639///
640/// @return the way the diff node matching the current suppression
641/// specification is to be reached.
644{return priv_->reach_kind_;}
645
646/// Setter of the way the diff node matching the current suppression
647/// specification is to be reached.
648///
649/// @param p the way the diff node matching the current suppression
650/// specification is to be reached.
651void
653{priv_->reach_kind_ = k;}
654
655/// Getter of the "has_size_change" property.
656///
657/// @return the value of the "has_size_change" property.
658bool
660{return priv_->has_size_change_;}
661
662/// Setter of the "has_size_change" property.
663///
664/// @param flag the new value of the "has_size_change" property.
665void
667{priv_->has_size_change_ = flag;}
668
669/// Getter of the "potential_data_member_names" property.
670///
671/// @return the set of potential data member names of this
672/// suppression.
673const unordered_set<string>&
675{return priv_->potential_data_members_;}
676
677/// Setter of the "potential_data_member_names" property.
678///
679/// @param s the new set of potential data member names of this
680/// suppression.
681void
683(const string_set_type& s) const
684{priv_->potential_data_members_ = s;}
685
686/// Getter of the "potential_data_member_names_regex" string.
687///
688/// @return the "potential_data_member_names_regex" string.
689const string&
691{return priv_->potential_data_members_regex_str_;}
692
693/// Setter of the "potential_data_member_names_regex" string.
694///
695/// @param d the new "potential_data_member_names_regex" string.
696void
698(const string& d) const
699{priv_->potential_data_members_regex_str_ = d;}
700
701/// Setter for the vector of data member insertion ranges that
702/// specifies where a data member is inserted as far as this
703/// suppression specification is concerned.
704///
705/// @param r the new insertion range vector.
706void
708{priv_->insertion_ranges_ = r;}
709
710/// Getter for the vector of data member insertion range that
711/// specifiers where a data member is inserted as far as this
712/// suppression specification is concerned.
713///
714/// @return the vector of insertion ranges.
717{return priv_->insertion_ranges_;}
718
719/// Getter for the vector of data member insertion range that
720/// specifiers where a data member is inserted as far as this
721/// suppression specification is concerned.
722///
723/// @return the vector of insertion ranges.
726{return priv_->insertion_ranges_;}
727
728/// Getter for the array of source location paths of types that should
729/// *NOT* be suppressed.
730///
731/// @return the set of source locations of types that should *NOT* be
732/// supressed.
733const unordered_set<string>&
735{return priv_->source_locations_to_keep_;}
736
737/// Getter for the array of source location paths of types that should
738/// *NOT* be suppressed.
739///
740/// @return the array of source locations of types that should *NOT*
741/// be supressed.
742unordered_set<string>&
744{return priv_->source_locations_to_keep_;}
745
746/// Setter for the array of source location paths of types that should
747/// *NOT* be suppressed.
748///
749/// @param l the new array.
750void
752(const unordered_set<string>& l)
753{priv_->source_locations_to_keep_ = l;}
754
755/// Getter of the regular expression string that designates the source
756/// location paths of types that should not be suppressed.
757///
758/// @return the regular expression string.
759const string&
761{return priv_->source_location_to_keep_regex_str_;}
762
763/// Setter of the regular expression string that designates the source
764/// location paths of types that should not be suppressed.
765///
766/// @param r the new regular expression.
767void
769{priv_->source_location_to_keep_regex_str_ = r;}
770
771/// Getter of the vector of the changed enumerators that are supposed
772/// to be suppressed. Note that this will be "valid" only if the type
773/// suppression has the 'type_kind = enum' property.
774///
775/// @return the vector of the changed enumerators that are supposed to
776/// be suppressed.
777const vector<string>&
779{return priv_->changed_enumerator_names_;}
780
781/// Setter of the vector of changed enumerators that are supposed to
782/// be suppressed. Note that this will be "valid" only if the type
783/// suppression has the 'type_kind = enum' property.
784///
785/// @param n the vector of the changed enumerators that are supposed
786/// to be suppressed.
787void
789{priv_->changed_enumerator_names_ = n;}
790
791/// Getter of the vector of the regular expression strings for changed
792/// enumerators that are supposed to be suppressed. Note that this
793/// will be "valid" only if the type suppression has the
794/// 'type_kind = enum' property.
795///
796/// @return the vector of the regular expression strings that are
797/// supposed to match enumertor names to be suppressed.
798const vector<regex::regex_t_sptr>&
800{return priv_->changed_enumerators_regexp_;}
801
802/// Setter of the vector of the regular expression strings for changed
803/// enumerators that are supposed to be suppressed. Note that this
804/// will be "valid" only if the type suppression has the
805/// 'type_kind = enum' property.
806///
807/// @param n the vector of the regular expression strings that are
808/// supposed to match enumertor names to be suppressed.
809void
810type_suppression::set_changed_enumerators_regexp(const vector<regex::regex_t_sptr>& n)
811{priv_->changed_enumerators_regexp_ = n;}
812
813/// Getter of the "has_string_fam_conversion" property.
814///
815/// @return the value of the "has_string_fam_conversion" property.
816bool
818{return priv_->has_strict_fam_conv_;}
819
820/// Setter of the "has_string_fam_conversion" property.
821///
822/// @param f the new value of the "has_string_fam_conversion"
823/// property.
824void
826{priv_->has_strict_fam_conv_ = f;}
827
828/// Evaluate this suppression specification on a given diff node and
829/// say if the diff node should be suppressed or not.
830///
831/// @param diff the diff node to evaluate this suppression
832/// specification against.
833///
834/// @return true if @p diff should be suppressed.
835bool
837{
838 const type_diff_base* d = is_type_diff(diff);
839 if (!d)
840 {
841 // So the diff we are looking at is not a type diff. However,
842 // there are cases where a type suppression can suppress changes
843 // on functions.
844
845 // Typically, if a virtual member function's virtual index (its
846 // index in the vtable of a class) changes and if the current
847 // type suppression is meant to suppress change reports about
848 // the enclosing class of the virtual member function, then this
849 // type suppression should suppress reports about that function
850 // change.
852 if (d)
853 {
854 // Let's see if 'd' carries a virtual member function
855 // change.
856 if (comparison::filtering::has_virtual_mem_fn_change(d))
857 {
859 class_decl_sptr fc =
860 is_class_type(is_method_type(f->get_type())->get_class_type());
861 ABG_ASSERT(fc);
862 if (suppresses_type(fc, diff->context()))
863 return true;
864 }
865 }
866 return false;
867 }
868
869 // If the suppression should consider the way the diff node has been
870 // reached, then do it now.
872 {
874 {
875 if (const pointer_diff* ptr_diff = is_pointer_diff(diff))
876 {
877 d = is_type_diff(ptr_diff->underlying_type_diff().get());
878 if (!d)
879 // This might be of, e.g, distinct_diff type.
880 return false;
882 }
883 else
884 return false;
885 }
887 {
888 if (const reference_diff* ref_diff = is_reference_diff(diff))
889 {
890 d = is_type_diff(ref_diff->underlying_type_diff().get());
891 if (!d)
892 // This might be of, e.g, distinct_diff type.
893 return false;
895 }
896 else
897 return false;
898 }
900 {
901 if (const pointer_diff* ptr_diff = is_pointer_diff(diff))
902 {
903 d = is_type_diff(ptr_diff->underlying_type_diff().get());
904 ABG_ASSERT(d);
906 }
907 else if (const reference_diff* ref_diff = is_reference_diff(diff))
908 {
909 d = is_type_diff(ref_diff->underlying_type_diff().get());
910 ABG_ASSERT(d);
912 }
913 else
914 return false;
915 }
916 }
917
918 type_base_sptr ft, st;
919 ft = is_type(d->first_subject());
920 st = is_type(d->second_subject());
921 ABG_ASSERT(ft && st);
922
923 if (!suppresses_type(ft, d->context())
924 && !suppresses_type(st, d->context()))
925 {
926 // A private type suppression specification considers that a
927 // type can be private and yet some typedefs of that type can be
928 // public -- depending on, e.g, if the typedef is defined in a
929 // public header or not. So if we are in the context of a
930 // private type suppression let's *NOT* peel typedefs away.
931 if (!is_opaque_type_suppr_spec(*this))
932 {
933 ft = peel_typedef_type(ft);
934 st = peel_typedef_type(st);
935 }
936
937 if (!suppresses_type(ft, d->context())
938 && !suppresses_type(st, d->context()))
939 return false;
940
942 }
943
944 // Now let's consider class diffs in the context of a suppr spec
945 // that contains properties like "has_data_member_inserted_*".
946
947 const class_or_union_diff* cou_diff = is_class_or_union_diff(d);
948 if (cou_diff)
949 {
950 class_or_union_sptr f = cou_diff->first_class_or_union();
951 // We are looking at the a class or union diff ...
952 if (!get_potential_data_member_names().empty())
953 {
954 // ... and the suppr spec has a:
955 //
956 // "has_data_member = {foo, bar}" property
957 //
958 for (string var_name : get_potential_data_member_names())
959 if (!f->find_data_member(var_name))
960 return false;
961 }
962
964 {
965 if (const regex_t_sptr& data_member_name_regex =
966 priv_->get_potential_data_member_names_regex())
967 {
968 bool data_member_matched = false;
969 for (var_decl_sptr dm : f->get_data_members())
970 {
971 if (regex::match(data_member_name_regex, dm->get_name()))
972 {
973 data_member_matched = true;
974 break;
975 }
976 }
977 if (!data_member_matched)
978 return false;
979 }
980 }
981 }
982
983 // Evaluate has_data_member_inserted_*" clauses.
984 const class_diff* klass_diff = dynamic_cast<const class_diff*>(d);
985 if (klass_diff)
986 {
987 const class_decl_sptr& first_class =
988 klass_diff->first_class_decl();
989 const class_decl_sptr& second_class =
990 klass_diff->second_class_decl();
991
992 // We are looking at a class diff ...
994 {
995 // ... and the suppr spec contains a
996 // "has_data_member_inserted_*" clause ...
997 if ((klass_diff->first_class_decl()->get_size_in_bits()
998 == klass_diff->second_class_decl()->get_size_in_bits())
1000 {
1001 // That "has_data_member_inserted_*" clause doesn't hold
1002 // if the class changed size, unless the user specified
1003 // that suppression applies to types that have size
1004 // change.
1005
1006 if (klass_diff->inserted_data_members().empty()
1007 && klass_diff->changed_data_members().empty())
1008 // So there is a has_data_member_inserted_* clause,
1009 // but no data member was inserted. That means the
1010 // clause is falsified.
1011 return false;
1012
1013 // All inserted data members must be in an allowed
1014 // insertion range.
1015 for (const auto& m : klass_diff->inserted_data_members())
1016 {
1017 decl_base_sptr member = m.second;
1018 bool matched = false;
1019
1020 for (const auto& range : get_data_member_insertion_ranges())
1022 range,
1023 first_class.get()))
1024 matched = true;
1025
1026 if (!matched)
1027 return false;
1028 }
1029
1030 // Similarly, each data member that replaced another one
1031 // must be in an allowed insertion range.
1032 for (const auto& m : klass_diff->changed_data_members())
1033 {
1034 var_decl_sptr member = m.second->second_var();
1035 bool matched = false;
1036
1037 for (const auto& range : get_data_member_insertion_ranges())
1038 if (is_data_member_offset_in_range(member, range,
1039 first_class.get()))
1040 matched = true;
1041
1042 if (!matched)
1043 return false;
1044 }
1045 }
1046 else
1047 return false;
1048 }
1049
1050 // Support for the
1051 // "has_strict_flexible_array_data_member_conversion = true"
1052 // clause.
1054 {
1055 // Let's detect if the first class of the diff has a fake
1056 // flexible array data member that got turned into a real
1057 // flexible array data member.
1058 if (!((get_has_size_change() || ((first_class->get_size_in_bits()
1059 == second_class->get_size_in_bits())))
1061 return false;
1062 }
1063 }
1064
1065 const enum_diff* enum_dif = dynamic_cast<const enum_diff*>(d);
1066 if (// We are looking at an enum diff node which ...
1067 enum_dif
1068 //... carries no deleted enumerator ... "
1069 && enum_dif->deleted_enumerators().empty()
1070 // ... carries no size change ...
1071 && (enum_dif->first_enum()->get_size_in_bits()
1072 == enum_dif->second_enum()->get_size_in_bits())
1073 // ... and yet carries some changed enumerators!
1074 && !enum_dif->changed_enumerators().empty())
1075 {
1076
1077 // Make sure that all changed enumerators are either:
1078 // 1. listed in the vector of enumerator names returned
1079 // by the get_changed_enumerator_names() member function
1080 // 2. match a regular expression returned by the
1081 // get_changed_enumerators_regexp() member function
1082 bool matched = true;
1083 for (string_changed_enumerator_map::const_iterator i =
1084 enum_dif->changed_enumerators().begin();
1085 i != enum_dif->changed_enumerators().end();
1086 ++i)
1087 {
1088 matched &= true;
1089 if ((std::find(get_changed_enumerator_names().begin(),
1091 i->first) == get_changed_enumerator_names().end())
1092 &&
1093 (std::find_if(get_changed_enumerators_regexp().begin(),
1095 [&] (const regex_t_sptr& enum_regexp)
1096 {
1097 return regex::match(enum_regexp, i->first);
1098 }) == get_changed_enumerators_regexp().end()))
1099 {
1100 matched &= false;
1101 break;
1102 }
1103 }
1104 if (!matched)
1105 return false;
1106 }
1107
1108 return true;
1109}
1110
1111/// Test if the current instance of @ref type_suppression suppresses a
1112/// change reports about a given type.
1113///
1114/// @param type the type to consider.
1115///
1116/// @param ctxt the context of comparison we are involved with.
1117///
1118/// @return true iff the suppression specification suppresses type @p
1119/// type.
1120bool
1121type_suppression::suppresses_type(const type_base_sptr& type,
1122 const diff_context_sptr& ctxt) const
1123{
1124 if (ctxt)
1125 {
1126 // Check if the names of the binaries match the suppression
1127 if (!names_of_binaries_match(*this, *ctxt))
1129 return false;
1130
1131 // Check if the sonames of the binaries match the suppression
1132 if (!sonames_of_binaries_match(*this, *ctxt))
1134 return false;
1135 }
1136
1137 return suppresses_type(type);
1138}
1139
1140/// Test if an instance of @ref type_suppression matches a given type.
1141///
1142/// This function does not take the name of the type into account
1143/// while testing if the type matches the type_suppression.
1144///
1145/// @param s the suppression to evaluate.
1146///
1147/// @param type the type to consider.
1148///
1149/// @return true iff the suppression specification matches type @p
1150/// type without taking its name into account.
1151static bool
1152suppression_matches_type_no_name(const type_suppression& s,
1153 const type_base_sptr &type)
1154{
1155 // If the suppression should consider type kind then, well, check
1156 // for that.
1157 if (s.get_consider_type_kind())
1158 {
1160 bool matches = true;
1161 switch (tk)
1162 {
1163 case type_suppression::UNKNOWN_TYPE_KIND:
1164 case type_suppression::CLASS_TYPE_KIND:
1165 if (!is_class_type(type))
1166 matches = false;
1167 break;
1168 case type_suppression::STRUCT_TYPE_KIND:
1169 {
1170 class_decl_sptr klass = is_class_type(type);
1171 if (!klass || !klass->is_struct())
1172 matches = false;
1173 }
1174 break;
1175 case type_suppression::UNION_TYPE_KIND:
1176 if (!is_union_type(type))
1177 matches = false;
1178 break;
1179 case type_suppression::ENUM_TYPE_KIND:
1180 if (!is_enum_type(type))
1181 matches = false;
1182 break;
1183 case type_suppression::ARRAY_TYPE_KIND:
1184 if (!is_array_type(type))
1185 matches = false;
1186 break;
1187 case type_suppression::TYPEDEF_TYPE_KIND:
1188 if (!is_typedef(type))
1189 matches = false;
1190 break;
1191 case type_suppression::BUILTIN_TYPE_KIND:
1192 if (!is_type_decl(type))
1193 matches = false;
1194 break;
1195 }
1196
1197 if (!matches)
1198 return false;
1199 }
1200
1201 // Check if there is a source location related match.
1203 return false;
1204
1205 return true;
1206}
1207
1208/// Test if a type suppression specification matches a type name.
1209///
1210/// @param s the type suppression to consider.
1211///
1212/// @param type_name the type name to consider.
1213///
1214/// @return true iff the type designated by its name @p type_name is
1215/// matched by the type suppression specification @p s.
1216bool
1218 const string& type_name)
1219{
1220 if (!s.get_type_name().empty()
1221 || s.priv_->get_type_name_regex()
1222 || s.priv_->get_type_name_not_regex())
1223 {
1224 // Check if there is an exact type name match.
1225 if (!s.get_type_name().empty())
1226 {
1227 if (s.get_type_name() != type_name)
1228 return false;
1229 }
1230 else
1231 {
1232 // Now check if there is a regular expression match.
1233 //
1234 // If the qualified name of the considered type doesn't match
1235 // the regular expression of the type name, then this
1236 // suppression doesn't apply.
1237 if (const regex_t_sptr& type_name_regex =
1238 s.priv_->get_type_name_regex())
1239 {
1240 if (!regex::match(type_name_regex, type_name))
1241 return false;
1242 }
1243
1244 if (const regex_t_sptr type_name_not_regex =
1245 s.priv_->get_type_name_not_regex())
1246 {
1247 if (regex::match(type_name_not_regex, type_name))
1248 return false;
1249 }
1250 }
1251 }
1252
1253 return true;
1254}
1255
1256/// Test if a type suppression matches a type in a particular scope.
1257///
1258/// @param s the type suppression to consider.
1259///
1260/// @param type_scope the scope of the type to consider.
1261///
1262/// @param type the type to consider.
1263///
1264/// @return true iff the supression @p s matches type @p type in scope
1265/// @p type_scope.
1266bool
1268 const scope_decl* type_scope,
1269 const type_base_sptr& type)
1270{
1271 string type_name = build_qualified_name(type_scope, type);
1272 return suppression_matches_type_name(s, type_name);
1273}
1274
1275/// Test if a type suppression matches a source location.
1276///
1277/// @param s the type suppression to consider.
1278///
1279/// @param loc the location to consider.
1280///
1281/// @return true iff the suppression @p s matches location @p loc.
1282bool
1284 const location& loc)
1285{
1286 if (loc)
1287 {
1288 // Check if there is a source location related match.
1289 string loc_path, loc_path_base;
1290 unsigned loc_line = 0, loc_column = 0;
1291 loc.expand(loc_path, loc_line, loc_column);
1292
1293 if (regex_t_sptr regexp = s.priv_->get_source_location_to_keep_regex())
1294 if (regex::match(regexp, loc_path))
1295 return false;
1296
1297 tools_utils::base_name(loc_path, loc_path_base);
1298 if (s.get_source_locations_to_keep().find(loc_path_base)
1299 != s.get_source_locations_to_keep().end())
1300 return false;
1301 if (s.get_source_locations_to_keep().find(loc_path)
1302 != s.get_source_locations_to_keep().end())
1303 return false;
1304 }
1305 else
1306 {
1307 if (!s.get_source_locations_to_keep().empty()
1308 || s.priv_->get_source_location_to_keep_regex())
1309 // The user provided a "source_location_not_regexp" or
1310 // a "source_location_not_in" property that was not
1311 // triggered. This means the current type suppression
1312 // doesn't suppress the type given.
1313 return false;
1314 }
1315
1316 return true;
1317}
1318
1319/// Test if a type suppression matches a type.
1320///
1321/// @param s the type suppression to consider.
1322///
1323/// @param type the type to consider.
1324///
1325/// @return true iff the suppression @p s matches type @p type.
1326bool
1328 const type_base_sptr& type)
1329{
1330 location loc = get_location(type);
1331 if (loc)
1332 return suppression_matches_type_location(s, loc);
1333 else
1334 {
1335 // The type had no source location.
1336 //
1337 // In the case where this type suppression was automatically
1338 // generated to suppress types not defined in public
1339 // headers, then this might mean that the type is not
1340 // defined in the public headers. Otherwise, why does it
1341 // not have a source location?
1342 if (s.get_is_artificial())
1343 {
1344 if (class_decl_sptr cl = is_class_type(type))
1345 {
1346 if (cl->get_is_declaration_only())
1347 // We tried hard above to get the definition of
1348 // the declaration. If we reach this place, it
1349 // means the class has no definition at this point.
1350 ABG_ASSERT(!cl->get_definition_of_declaration());
1352 // So this looks like what really amounts to an
1353 // opaque type. So it's not defined in the public
1354 // headers. So we want to filter it out.
1355 return true;
1356 }
1357 }
1358 if (!s.get_source_locations_to_keep().empty()
1359 || s.priv_->get_source_location_to_keep_regex())
1360 // The user provided a "source_location_not_regexp" or
1361 // a "source_location_not_in" property that was not
1362 // triggered. This means the current type suppression
1363 // doesn't suppress the type given.
1364 return false;
1365 }
1366
1367 return true;
1368}
1369
1370/// Test if a type suppression matches a type name and location.
1371///
1372/// @param s the type suppression to consider.
1373///
1374/// @param type_name the name of the type to consider.
1375///
1376/// @param type_location the location of the type to consider.
1377///
1378/// @return true iff suppression @p s matches a type named @p
1379/// type_name with a location @p type_location.
1380bool
1382 const string& type_name,
1383 const location& type_location)
1384{
1385 if (!suppression_matches_type_name(s, type_name))
1386 return false;
1387 if (!suppression_matches_type_location(s, type_location))
1388 return false;
1389 return true;
1390}
1391
1392/// Test if the current instance of @ref type_suppression matches a
1393/// given type.
1394///
1395/// @param type the type to consider.
1396///
1397/// @return true iff the suppression specification suppresses type @p
1398/// type.
1399bool
1400type_suppression::suppresses_type(const type_base_sptr& type) const
1401{
1402 if (!suppression_matches_type_no_name(*this, type))
1403 return false;
1404
1405 if (!suppression_matches_type_name(*this, get_name(type)))
1406 return false;
1407
1408 return true;
1409}
1410
1411/// Test if the current instance of @ref type_suppression matches a
1412/// given type in a given scope.
1413///
1414/// @param type the type to consider.
1415///
1416/// @param type_scope the scope of type @p type.
1417///
1418/// @return true iff the suppression specification suppresses type @p
1419/// type from scope @p type_scope.
1420bool
1421type_suppression::suppresses_type(const type_base_sptr& type,
1422 const scope_decl* type_scope) const
1423{
1424 if (!suppression_matches_type_no_name(*this, type))
1425 return false;
1426
1427 if (!suppression_matches_type_name(*this, type_scope, type))
1428 return false;
1429
1430 return true;
1431}
1432
1433/// The private data of type_suppression::insertion_range
1434struct type_suppression::insertion_range::priv
1435{
1436 boundary_sptr begin_;
1437 boundary_sptr end_;
1438
1439 priv()
1440 {}
1441
1443 : begin_(begin), end_(end)
1444 {}
1445}; // end struct type_suppression::insertion_range::priv
1446
1447/// Default Constructor of @ref type_suppression::insertion_range.
1451
1452/// Constructor of @ref type_suppression::insertion_range.
1453///
1454/// @param begin the start of the range. A range boundary that is an
1455/// instance of @ref interger_boundary with a negative value means the
1456/// maximum possible value.
1457///
1458/// @param end the end of the range. A range boundary that is an
1459/// instance of @ref interger_boundary with a negative value means the
1460/// maximum possible value.
1462 boundary_sptr end)
1463 : priv_(new priv(begin, end))
1464{}
1465
1466/// Getter for the beginning of the range.
1467///
1468/// @return the beginning of the range. A range boundary that is an
1469/// instance of @ref interger_boundary with a negative value means the
1470/// maximum possible value.
1473{return priv_->begin_;}
1474
1475/// Getter for the end of the range.
1476///
1477/// @return the end of the range. A range boundary that is an
1478/// instance of @ref interger_boundary with a negative value means the
1479/// maximum possible value.
1482{return priv_->end_;}
1483
1484/// Create an integer boundary.
1485///
1486/// The return value of this function is to be used as a boundary for
1487/// an instance of @ref type_suppression::insertion_range. That
1488/// boundary evaluates to an integer value.
1489///
1490/// @param value the value of the integer boundary.
1491///
1492/// @return the resulting integer boundary.
1496
1497/// Create a function call expression boundary.
1498///
1499/// The return value of this function is to be used as a boundary for
1500/// an instance of @ref type_suppression::insertion_range. The value
1501/// of that boundary is actually a function call expression that
1502/// itself evalutates to an integer value, in the context of a @ref
1503/// class_decl.
1504///
1505/// @param expr the function call expression to create the boundary from.
1506///
1507/// @return the resulting function call expression boundary.
1511
1512/// Create a function call expression boundary.
1513///
1514/// The return value of this function is to be used as a boundary for
1515/// an instance of @ref type_suppression::insertion_range. The value
1516/// of that boundary is actually a function call expression that
1517/// itself evalutates to an integer value, in the context of a @ref
1518/// class_decl.
1519///
1520/// @param s a string representing the expression the function call
1521/// expression to create the boundary from.
1522///
1523/// @return the resulting function call expression boundary.
1526{
1527 fn_call_expr_boundary_sptr result, nil;
1529 if (ini::read_function_call_expr(s, expr) && expr)
1530 result.reset(new fn_call_expr_boundary(expr));
1531 return result;
1532}
1533
1534/// Create a named boundary.
1535///
1536/// The return value is to be used as a boundary for an instance of
1537/// @ref type_suppression::insertion_range. The value of that
1538/// boundary is a named constant that is to be evaluated to an integer
1539/// value, in the context of a @ref class_decl. That evaluate is
1540/// performed by the function
1541/// type_suppression::insertion_range::eval_boundary().
1542///
1543/// @param name the name of the boundary.
1544///
1545/// @return the newly created named boundary.
1548{
1549 named_boundary_sptr result(new named_boundary(name));
1550 return result;
1551}
1552
1553/// Evaluate an insertion range boundary to get a resulting integer
1554/// value.
1555///
1556/// @param boundary the boundary to evaluate.
1557///
1558/// @param context the context of evualuation. It's a @ref class_decl
1559/// to take into account during the evaluation, if there is a need for
1560/// it.
1561///
1562/// @return true iff the evaluation was successful and @p value
1563/// contains the resulting value.
1564bool
1566 const class_or_union* context,
1567 uint64_t& value)
1568{
1570 {
1571 value = b->as_integer();
1572 return true;
1573 }
1575 {
1576 ini::function_call_expr_sptr fn_call = b->as_function_call_expr();
1577 if (fn_call
1578 && (fn_call->get_name() == "offset_of"
1579 || fn_call->get_name() == "offset_after"
1580 || fn_call->get_name() == "offset_of_first_data_member_regexp"
1581 || fn_call->get_name() == "offset_of_last_data_member_regexp")
1582 && fn_call->get_arguments().size() == 1)
1583 {
1584 if (fn_call->get_name() == "offset_of"
1585 || fn_call->get_name() == "offset_after")
1586 {
1587 string member_name = fn_call->get_arguments()[0];
1588 for (class_decl::data_members::const_iterator it =
1589 context->get_data_members().begin();
1590 it != context->get_data_members().end();
1591 ++it)
1592 {
1593 if (!get_data_member_is_laid_out(**it))
1594 continue;
1595 if ((*it)->get_name() == member_name)
1596 {
1597 if (fn_call->get_name() == "offset_of")
1598 value = get_data_member_offset(*it);
1599 else if (fn_call->get_name() == "offset_after")
1600 {
1601 if (!get_next_data_member_offset(context, *it, value))
1602 {
1603 value = get_data_member_offset(*it) +
1604 (*it)->get_type()->get_size_in_bits();
1605 }
1606 }
1607 else
1608 // We should not reach this point.
1609 abort();
1610 return true;
1611 }
1612 }
1613 }
1614 else if (fn_call->get_name() == "offset_of_first_data_member_regexp"
1615 || fn_call->get_name() == "offset_of_last_data_member_regexp")
1616 {
1617 string name_regexp = fn_call->get_arguments()[0];
1618 auto r = regex::compile(name_regexp);
1619 var_decl_sptr dm;
1620
1621 if (fn_call->get_name() == "offset_of_first_data_member_regexp")
1623 else if (fn_call->get_name() == "offset_of_last_data_member_regexp")
1624 dm = find_last_data_member_matching_regexp(*context, r);
1625
1626 if (dm)
1627 {
1628 value = get_data_member_offset(dm);
1629 return true;
1630 }
1631 }
1632 }
1633 }
1635 {
1636 if (b->get_name() == OFFSET_OF_FLEXIBLE_ARRAY_DATA_MEMBER_STRING())
1637 {
1638 // Look at the last data member of 'context' and make sure
1639 // its type is an array with non-finite size.
1641 {
1642 value = get_data_member_offset(dm);
1643 return true;
1644 }
1645 }
1646 else if (b->get_name() == END_STRING())
1647 {
1648 // The 'end' of a struct is represented by the value
1649 // std::numeric_limits<uint64_t>::max(), recognized by
1650 // type_suppression::insertion_range::boundary_value_is_end.
1651 value = std::numeric_limits<uint64_t>::max();
1652 return true;
1653 }
1654 }
1655 return false;
1656}
1657
1658/// Test if a given value supposed to be inside an insertion range
1659/// represents the end of the range.
1660///
1661/// @param value the value to test for.
1662///
1663/// @return true iff @p value represents the end of the insertion
1664/// range.
1665bool
1667{
1668 return value == std::numeric_limits<uint64_t>::max();
1669}
1670
1671/// Tests if a given instance of @ref
1672/// type_suppression::insertion_range::boundary is actually an integer boundary.
1673///
1674/// @param b the boundary to test.
1675///
1676/// @return a pointer to the instance of
1677/// type_suppression::insertion_range::integer_boundary if @p b is
1678/// actually an integer boundary. Otherwise, return a null pointer.
1681{return dynamic_pointer_cast<type_suppression::insertion_range::integer_boundary>(b);}
1682
1683/// Tests if a given instance of @ref
1684/// type_suppression::insertion_range::boundary is actually a
1685/// function call expression boundary.
1686///
1687/// @param b the boundary to test.
1688///
1689/// @return a pointer to the instance of
1690/// type_suppression::insertion_range::fn_call_expr_boundary if @p b
1691/// is actually an function call expression boundary. Otherwise,
1692/// return a null pointer.
1695{return dynamic_pointer_cast<type_suppression::insertion_range::fn_call_expr_boundary>(b);}
1696
1697/// Test if a given instance of @ref
1698/// type_suppression::insertion_range::boundary is actually a named boundary.
1699///
1700/// @param b the boundary to consider.
1701///
1702/// @return the instance of @ref
1703/// type_suppression::insertion_range::named_boundary if @p b is a
1704/// named boundary, or nil.
1707{return dynamic_pointer_cast<type_suppression::insertion_range::named_boundary>(b);}
1708
1709/// The private data type of @ref
1710/// type_suppression::insertion_range::boundary.
1711struct type_suppression::insertion_range::boundary::priv
1712{
1713 priv()
1714 {}
1715}; // end struct type_suppression::insertion_range::boundary::priv
1716
1717/// Default constructor of @ref
1718/// type_suppression::insertion_range::boundary
1722
1723/// Destructor of @ref type_suppression::insertion_range::boundary.
1726
1727/// Private data type for @ref
1728/// type_suppression::insertion_range::integer_boundary.
1729struct type_suppression::insertion_range::integer_boundary::priv
1730{
1731 uint64_t value_;
1732
1733 priv()
1734 : value_()
1735 {}
1736
1737 priv(uint64_t value)
1738 : value_(value)
1739 {}
1740}; // end type_suppression::insertion_range::integer_boundary::priv
1741
1742/// Converting constructor of
1743/// type_suppression::insertion_range::integer_boundary.
1744///
1745/// @param value the integer value of the newly created integer boundary.
1746type_suppression::insertion_range::integer_boundary::integer_boundary(uint64_t value)
1747 : priv_(new priv(value))
1748{}
1749
1750/// Return the integer value of the current instance of @ref
1751/// type_suppression::insertion_range::integer_boundary.
1752///
1753/// @return the integer value of the current boundary.
1754uint64_t
1757
1758/// Converts the current boundary into an integer value.
1759///
1760/// @return the integer value of the current boundary.
1761type_suppression::insertion_range::integer_boundary::operator uint64_t() const
1762{return as_integer();}
1763
1764/// Destructor of @ref type_suppression::insertion_range::integer_boundary.
1767
1768/// Private data type of type @ref
1769/// type_suppression::insertion_range::fn_call_expr_boundary.
1770struct type_suppression::insertion_range::fn_call_expr_boundary::priv
1771{
1773
1774 priv()
1775 {}
1776
1778 : expr_(expr)
1779 {}
1780}; // end struct type_suppression::insertion_range::fn_call_expr_boundary::priv
1781
1782/// Converting constructor for @ref
1783/// type_suppression::insertion_range::fn_call_expr_boundary.
1784///
1785/// @param expr the function call expression to build this boundary
1786/// from.
1787type_suppression::insertion_range::fn_call_expr_boundary::
1788fn_call_expr_boundary(ini::function_call_expr_sptr expr)
1789 : priv_(new priv(expr))
1790{}
1791
1792/// Returns the function call expression value of the current boundary.
1793///
1794/// @return the function call expression value of the current boundary;
1798
1799/// Converts the current boundary to its function call expression value.
1800///
1801/// @return the function call expression value of the current boundary.
1802type_suppression::insertion_range::fn_call_expr_boundary::operator ini::function_call_expr_sptr () const
1803{return as_function_call_expr();}
1804
1805/// Destructor of @ref
1806/// type_suppression::insertion_range::fn_call_expr_boundary.
1809
1810/// The private data type for the @ref
1811/// type_suppression::insertion_range::named_boundary.
1812struct type_suppression::insertion_range::named_boundary::priv
1813{
1814 string name_;
1815
1816 priv()
1817 {}
1818
1819 priv(const string& name)
1820 : name_(name)
1821 {}
1822}; // end struct type_suppression::insertion_range::named_boundary::priv
1823
1824/// Constructor for @ref
1825/// type_suppression::insertion_range::named_boundary
1826///
1827/// @param name the name of the @ref named_boundary type.
1828type_suppression::insertion_range::named_boundary::named_boundary(const string& name)
1829 : priv_(new priv(name))
1830{}
1831
1832/// Getter for the name of the named boundary.
1833///
1834/// @return the name of the named boundary.
1835const string&
1838
1839/// Test if an instance of @ref suppression is an instance of @ref
1840/// type_suppression.
1841///
1842/// @param suppr the instance of @ref suppression to test for.
1843///
1844/// @return if @p suppr is an instance of @ref type_suppression, then
1845/// return the sub-object of the @p suppr of type @ref
1846/// type_suppression, otherwise return a nil pointer.
1849{return dynamic_pointer_cast<type_suppression>(suppr);}
1850
1851// </type_suppression stuff>
1852
1853// <negated_type_suppression stuff>
1854
1855/// Constructor for @ref negated_type_suppression.
1856///
1857/// @param label the label of the suppression. This is just a free
1858/// form comment explaining what the suppression is about.
1859///
1860/// @param type_name_regexp the regular expression describing the
1861/// types about which diff reports should be suppressed. If it's an
1862/// empty string, the parameter is ignored.
1863///
1864/// @param type_name the name of the type about which diff reports
1865/// should be suppressed. If it's an empty string, the parameter is
1866/// ignored.
1867///
1868/// Note that parameter @p type_name_regexp and @p type_name_regexp
1869/// should not necessarily be populated. It usually is either one or
1870/// the other that the user wants.
1872 const string& type_name_regexp,
1873 const string& type_name)
1874 : type_suppression(label, type_name_regexp, type_name),
1876{
1877}
1878
1879/// Evaluate this suppression specification on a given diff node and
1880/// say if the diff node should be suppressed or not.
1881///
1882/// @param diff the diff node to evaluate this suppression
1883/// specification against.
1884///
1885/// @return true if @p diff should be suppressed.
1886bool
1891
1892/// Destructor of the @ref negated_type_suppression type.
1896
1897// </negated_type_suppression stuff>
1898
1899/// Parse the value of the "type_kind" property in the "suppress_type"
1900/// section.
1901///
1902/// @param input the input string representing the value of the
1903/// "type_kind" property.
1904///
1905/// @return the @ref type_kind enumerator parsed.
1907read_type_kind_string(const string& input)
1908{
1909 if (input == "class")
1910 return type_suppression::CLASS_TYPE_KIND;
1911 else if (input == "struct")
1912 return type_suppression::STRUCT_TYPE_KIND;
1913 else if (input == "union")
1914 return type_suppression::UNION_TYPE_KIND;
1915 else if (input == "enum")
1916 return type_suppression::ENUM_TYPE_KIND;
1917 else if (input == "array")
1918 return type_suppression::ARRAY_TYPE_KIND;
1919 else if (input == "typedef")
1920 return type_suppression::TYPEDEF_TYPE_KIND;
1921 else if (input == "builtin")
1922 return type_suppression::BUILTIN_TYPE_KIND;
1923 else
1924 return type_suppression::UNKNOWN_TYPE_KIND;
1925}
1926
1927/// Parse the value of the "accessed_through" property in the
1928/// "suppress_type" section.
1929///
1930/// @param input the input string representing the value of the
1931/// "accessed_through" property.
1932///
1933/// @return the @ref type_suppression::reach_kind enumerator parsed.
1935read_suppression_reach_kind(const string& input)
1936{
1937 if (input == "direct")
1939 else if (input == "pointer")
1941 else if (input == "reference")
1943 else if (input == "reference-or-pointer")
1945 else
1947}
1948
1949/// Read a type suppression from an instance of ini::config::section
1950/// and build a @ref type_suppression as a result.
1951///
1952/// @param section the section of the ini config to read.
1953///
1954/// @return the resulting @ref type_suppression upon successful
1955/// parsing, or nil.
1957read_type_suppression(const ini::config::section& section)
1958{
1959 type_suppression_sptr result;
1960
1961 if (section.get_name() != "suppress_type"
1962 && section.get_name() != "allow_type")
1963 return result;
1964
1965 static const char *const sufficient_props[] = {
1966 "file_name_regexp",
1967 "file_name_not_regexp",
1968 "soname_regexp",
1969 "soname_not_regexp",
1970 "name",
1971 "name_regexp",
1972 "name_not_regexp",
1973 "type_kind",
1974 "source_location_not_in",
1975 "source_location_not_regexp",
1976 };
1977 if (!check_sufficient_props(sufficient_props,
1978 sizeof(sufficient_props)/sizeof(char*),
1979 section))
1980 return result;
1981
1982 ini::simple_property_sptr drop_artifact =
1983 is_simple_property(section.find_property("drop_artifact"));
1984 if (!drop_artifact)
1985 drop_artifact = is_simple_property(section.find_property("drop"));
1986
1987 string drop_artifact_str = drop_artifact
1988 ? drop_artifact->get_value()->as_string()
1989 : "";
1990
1991 ini::simple_property_sptr has_size_change =
1992 is_simple_property(section.find_property("has_size_change"));
1993
1994 string has_size_change_str = has_size_change
1995 ? has_size_change->get_value()->as_string()
1996 : "";
1997
1999 is_simple_property(section.find_property("label"));
2000 string label_str = label ? label->get_value()->as_string() : "";
2001
2002 ini::simple_property_sptr file_name_regex_prop =
2003 is_simple_property(section.find_property("file_name_regexp"));
2004 string file_name_regex_str =
2005 file_name_regex_prop ? file_name_regex_prop->get_value()->as_string() : "";
2006
2007 ini::simple_property_sptr file_name_not_regex_prop =
2008 is_simple_property(section.find_property("file_name_not_regexp"));
2009 string file_name_not_regex_str =
2010 file_name_not_regex_prop
2011 ? file_name_not_regex_prop->get_value()->as_string()
2012 : "";
2013
2014 ini::simple_property_sptr soname_regex_prop =
2015 is_simple_property(section.find_property("soname_regexp"));
2016 string soname_regex_str =
2017 soname_regex_prop ? soname_regex_prop->get_value()->as_string() : "";
2018
2019 ini::simple_property_sptr soname_not_regex_prop =
2020 is_simple_property(section.find_property("soname_not_regexp"));
2021 string soname_not_regex_str =
2022 soname_not_regex_prop
2023 ? soname_not_regex_prop->get_value()->as_string()
2024 : "";
2025
2026 ini::simple_property_sptr name_regex_prop =
2027 is_simple_property(section.find_property("name_regexp"));
2028 string name_regex_str = name_regex_prop
2029 ? name_regex_prop->get_value()->as_string()
2030 : "";
2031
2032 ini::simple_property_sptr name_not_regex_prop =
2033 is_simple_property(section.find_property("name_not_regexp"));
2034 string name_not_regex_str = name_not_regex_prop
2035 ? name_not_regex_prop->get_value()->as_string()
2036 : "";
2037
2038 ini::simple_property_sptr name_prop =
2039 is_simple_property(section.find_property("name"));
2040 string name_str = name_prop
2041 ? name_prop->get_value()->as_string()
2042 : "";
2043
2044 ini::property_sptr srcloc_not_in_prop =
2045 section.find_property("source_location_not_in");
2046 unordered_set<string> srcloc_not_in;
2047 if (srcloc_not_in_prop)
2048 {
2049 if (ini::simple_property_sptr p = is_simple_property(srcloc_not_in_prop))
2050 srcloc_not_in.insert(p->get_value()->as_string());
2051 else
2052 {
2053 ini::list_property_sptr list_property =
2054 is_list_property(srcloc_not_in_prop);
2055 if (list_property)
2056 {
2057 vector<string>::const_iterator i;
2058 for (i = list_property->get_value()->get_content().begin();
2059 i != list_property->get_value()->get_content().end();
2060 ++i)
2061 srcloc_not_in.insert(*i);
2062 }
2063 }
2064 }
2065
2066 ini::simple_property_sptr srcloc_not_regexp_prop =
2067 is_simple_property(section.find_property("source_location_not_regexp"));
2068 string srcloc_not_regexp_str;
2069 if (srcloc_not_regexp_prop)
2070 srcloc_not_regexp_str = srcloc_not_regexp_prop->get_value()->as_string();
2071
2072 bool consider_type_kind = false;
2073 type_suppression::type_kind type_kind = type_suppression::UNKNOWN_TYPE_KIND;
2074 if (ini::simple_property_sptr type_kind_prop =
2075 is_simple_property(section.find_property("type_kind")))
2076 {
2077 consider_type_kind = true;
2078 type_kind =
2079 read_type_kind_string(type_kind_prop->get_value()->as_string());
2080 }
2081
2082 bool consider_reach_kind = false;
2084 if (ini::simple_property_sptr reach_kind_prop =
2085 is_simple_property(section.find_property("accessed_through")))
2086 {
2087 consider_reach_kind = true;
2088 reach_kind =
2089 read_suppression_reach_kind(reach_kind_prop->get_value()->as_string());
2090 }
2091
2092 // Support has_data_member = {}
2093 string_set_type potential_data_member_names;
2094 if (ini::property_sptr propertee = section.find_property("has_data_member"))
2095 {
2096 // This is either has_data_member = {foo, blah} or
2097 // has_data_member = foo.
2100 if (ini::tuple_property_sptr prop = is_tuple_property(propertee))
2101 // Value is of the form {foo,blah}
2102 tv = prop->get_value();
2103 else if (ini::simple_property_sptr prop = is_simple_property(propertee))
2104 // Value is of the form foo.
2105 sv = prop->get_value();
2106
2107 // Ensure that the property value has the form {"foo", "blah", ...};
2108 // Meaning it's a tuple of one element which is a list or a string.
2109 if (tv
2110 && tv->get_value_items().size() == 1
2111 && (is_list_property_value(tv->get_value_items().front())
2112 || is_string_property_value(tv->get_value_items().front())))
2113 {
2115 is_list_property_value(tv->get_value_items().front());
2116 if (!val)
2117 {
2118 // We have just one potential data member name,as a
2119 // string_property_value.
2120 string name =
2121 is_string_property_value(tv->get_value_items().front())
2122 ->as_string();
2123 potential_data_member_names.insert(name);
2124 }
2125 else
2126 for (const string& name : val->get_content())
2127 potential_data_member_names.insert(name);
2128 }
2129 else if (sv)
2130 {
2131 string name = sv->as_string();
2132 potential_data_member_names.insert(name);
2133 }
2134 }
2135
2136 // Support has_data_member_regexp = str
2137 string potential_data_member_names_regexp_str;
2138 if (ini::simple_property_sptr prop =
2139 is_simple_property(section.find_property("has_data_member_regexp")))
2140 potential_data_member_names_regexp_str = prop->get_value()->as_string();
2141
2142 // Support has_data_member_inserted_at
2143 vector<type_suppression::insertion_range_sptr> insert_ranges;
2144 bool consider_data_member_insertion = false;
2145 if (ini::simple_property_sptr prop =
2146 is_simple_property(section.find_property("has_data_member_inserted_at")))
2147 {
2148 // So this property has the form:
2149 // has_data_member_inserted_at = <one-string-property-value>
2150 string ins_point = prop->get_value()->as_string();
2152 if (ins_point == END_STRING())
2154 else if (ins_point == OFFSET_OF_FLEXIBLE_ARRAY_DATA_MEMBER_STRING())
2156 else if (isdigit(ins_point[0]))
2158 (atoi(ins_point.c_str()));
2161 begin = expr;
2162 else
2163 return result;
2164
2167 (new type_suppression::insertion_range(begin, end));
2168 insert_ranges.push_back(insert_range);
2169 consider_data_member_insertion = true;
2170 }
2171
2172 // Support has_data_member_inserted_between
2173 if (ini::tuple_property_sptr prop =
2174 is_tuple_property(section.find_property
2175 ("has_data_member_inserted_between")))
2176 {
2177 // ensures that this has the form:
2178 // has_data_member_inserted_between = {0 , end};
2179 // and not (for instance):
2180 // has_data_member_inserted_between = {{0 , end}, {1, foo}}
2181 //
2182 // This means that the tuple_property_value contains just one
2183 // value, which is a list_property that itself contains 2
2184 // values.
2186 ini::tuple_property_value_sptr v = prop->get_value();
2187 if (v
2188 && v->get_value_items().size() == 1
2189 && is_list_property_value(v->get_value_items()[0])
2190 && is_list_property_value(v->get_value_items()[0])->get_content().size() == 2)
2191 {
2193 is_list_property_value(v->get_value_items()[0]);
2194 ABG_ASSERT(val);
2195 string str = val->get_content()[0];
2196 if (str == "end")
2197 begin =
2199 else if (isdigit(str[0]))
2201 (atoi(str.c_str()));
2204 begin = expr;
2205 else
2206 return result;
2207
2208 str = val->get_content()[1];
2209 if (str == "end")
2210 end =
2212 else if (isdigit(str[0]))
2214 (atoi(str.c_str()));
2217 end = expr;
2218 else
2219 return result;
2220
2222 (new type_suppression::insertion_range(begin, end));
2223 insert_ranges.push_back(insert_range);
2224 consider_data_member_insertion = true;
2225 }
2226 else
2227 // the 'has_data_member_inserted_between' property has a wrong
2228 // value type, so let's discard the endire [suppress_type]
2229 // section.
2230 return result;
2231 }
2232
2233 // Support has_data_members_inserted_between
2234 // The syntax looks like:
2235 //
2236 // has_data_members_inserted_between = {{8, 24}, {32, 64}, {128, end}}
2237 //
2238 // So we expect a tuple property, with potentially several pairs (as
2239 // part of the value); each pair designating a range. Note that
2240 // each pair (range) is a list property value.
2241 if (ini::tuple_property_sptr prop =
2242 is_tuple_property(section.find_property
2243 ("has_data_members_inserted_between")))
2244 {
2245 bool is_well_formed = true;
2246 for (vector<ini::property_value_sptr>::const_iterator i =
2247 prop->get_value()->get_value_items().begin();
2248 is_well_formed && i != prop->get_value()->get_value_items().end();
2249 ++i)
2250 {
2251 ini::tuple_property_value_sptr tuple_value =
2253 if (!tuple_value
2254 || tuple_value->get_value_items().size() != 1
2255 || !is_list_property_value(tuple_value->get_value_items()[0]))
2256 {
2257 is_well_formed = false;
2258 break;
2259 }
2261 is_list_property_value(tuple_value->get_value_items()[0]);
2262 if (list_value->get_content().size() != 2)
2263 {
2264 is_well_formed = false;
2265 break;
2266 }
2267
2269 string str = list_value->get_content()[0];
2270 if (str == "end")
2271 begin =
2273 else if (isdigit(str[0]))
2274 begin =
2276 (atoi(str.c_str()));
2279 begin = expr;
2280 else
2281 return result;
2282
2283 str = list_value->get_content()[1];
2284 if (str == "end")
2285 end =
2287 else if (isdigit(str[0]))
2289 (atoi(str.c_str()));
2292 end = expr;
2293 else
2294 return result;
2295
2297 (new type_suppression::insertion_range(begin, end));
2298 insert_ranges.push_back(insert_range);
2299 consider_data_member_insertion = true;
2300 }
2301 if (!is_well_formed)
2302 return result;
2303 }
2304
2305 /// Support 'changed_enumerators = foo, bar, baz'
2306 ///
2307 /// Note that this constraint is valid only if we have:
2308 /// 'type_kind = enum'.
2309 ///
2310 /// If the current type is an enum and if it carries changed
2311 /// enumerators listed in the changed_enumerators property value
2312 /// then it should be suppressed.
2313
2314 ini::property_sptr changed_enumerators_prop =
2315 section.find_property("changed_enumerators");
2316
2317 vector<string> changed_enumerator_names;
2318 if (changed_enumerators_prop)
2319 {
2321 is_list_property(changed_enumerators_prop))
2322 changed_enumerator_names =
2323 p->get_value()->get_content();
2324 else if (ini::simple_property_sptr p =
2325 is_simple_property(changed_enumerators_prop))
2326 changed_enumerator_names.push_back(p->get_value()->as_string());
2327 }
2328
2329 /// Support 'changed_enumerators_regexp = .*_foo, bar_[0-9]+, baz'
2330 ///
2331 /// If the current type is an enum and if it carries changed
2332 /// enumerators that match regular expressions listed in the
2333 /// changed_enumerators_regexp property value then it should be
2334 /// suppressed.
2335
2336 ini::property_sptr changed_enumerators_regexp_prop =
2337 section.find_property("changed_enumerators_regexp");
2338
2339 vector<regex_t_sptr> changed_enumerators_regexp;
2340 if (changed_enumerators_regexp_prop)
2341 {
2343 is_list_property(changed_enumerators_regexp_prop))
2344 {
2345 for (string e : p->get_value()->get_content())
2346 changed_enumerators_regexp.push_back(regex::compile(e));
2347 }
2348 else if (ini::simple_property_sptr p =
2349 is_simple_property(changed_enumerators_regexp_prop))
2350 {
2351 changed_enumerators_regexp.push_back(
2352 regex::compile(p->get_value()->as_string())
2353 );
2354 }
2355 }
2356
2357 // Support "has_strict_flexible_array_data_member_conversion"
2358 ini::simple_property_sptr has_strict_fam_conv =
2360 (section.find_property("has_strict_flexible_array_data_member_conversion"));
2361 string has_strict_fam_conv_str = has_strict_fam_conv
2362 ? has_strict_fam_conv->get_value()->as_string()
2363 : "";
2364
2365 if (section.get_name() == "suppress_type")
2366 result.reset(new type_suppression(label_str, name_regex_str, name_str));
2367 else if (section.get_name() == "allow_type")
2368 result.reset(new negated_type_suppression(label_str, name_regex_str,
2369 name_str));
2370
2371 if (consider_type_kind)
2372 {
2373 result->set_consider_type_kind(true);
2374 result->set_type_kind(type_kind);
2375 }
2376
2377 if (consider_reach_kind)
2378 {
2379 result->set_consider_reach_kind(true);
2380 result->set_reach_kind(reach_kind);
2381 }
2382
2383 if (!potential_data_member_names.empty())
2384 result->set_potential_data_member_names(potential_data_member_names);
2385
2386 if (!potential_data_member_names_regexp_str.empty())
2387 result->set_potential_data_member_names_regex_str
2388 (potential_data_member_names_regexp_str);
2389
2390 if (consider_data_member_insertion)
2391 result->set_data_member_insertion_ranges(insert_ranges);
2392
2393 if (!name_not_regex_str.empty())
2394 result->set_type_name_not_regex_str(name_not_regex_str);
2395
2396 if (!file_name_regex_str.empty())
2397 result->set_file_name_regex_str(file_name_regex_str);
2398
2399 if (!file_name_not_regex_str.empty())
2400 result->set_file_name_not_regex_str(file_name_not_regex_str);
2401
2402 if (!soname_regex_str.empty())
2403 result->set_soname_regex_str(soname_regex_str);
2404
2405 if (!soname_not_regex_str.empty())
2406 result->set_soname_not_regex_str(soname_not_regex_str);
2407
2408 if (!srcloc_not_in.empty())
2409 result->set_source_locations_to_keep(srcloc_not_in);
2410
2411 if (!srcloc_not_regexp_str.empty())
2412 result->set_source_location_to_keep_regex_str(srcloc_not_regexp_str);
2413
2414 if ((drop_artifact_str == "yes" || drop_artifact_str == "true")
2415 && ((!name_regex_str.empty()
2416 || !name_str.empty()
2417 || !srcloc_not_regexp_str.empty()
2418 || !srcloc_not_in.empty())))
2419 result->set_drops_artifact_from_ir(true);
2420
2421 if (has_size_change_str == "yes" || has_size_change_str == "true")
2422 result->set_has_size_change(true);
2423
2424 if (result->get_type_kind() == type_suppression::ENUM_TYPE_KIND
2425 && !changed_enumerator_names.empty())
2426 result->set_changed_enumerator_names(changed_enumerator_names);
2427
2428 if (result->get_type_kind() == type_suppression::ENUM_TYPE_KIND
2429 && !changed_enumerators_regexp.empty())
2430 result->set_changed_enumerators_regexp(changed_enumerators_regexp);
2431
2432 if (has_strict_fam_conv_str == "yes" || has_strict_fam_conv_str == "true")
2433 result->set_has_strict_fam_conversion(true);
2434
2435 return result;
2436}
2437
2438// <function_suppression stuff>
2439
2440/// Constructor for the @ref the function_suppression::parameter_spec
2441/// type.
2442///
2443/// @param i the index of the parameter designated by this specification.
2444///
2445/// @param tn the type name of the parameter designated by this specification.
2446///
2447/// @param tn_regex a regular expression that defines a set of type
2448/// names for the parameter designated by this specification. Note
2449/// that at evaluation time, this regular expression is taken in
2450/// account only if the parameter @p tn is empty.
2451function_suppression::parameter_spec::parameter_spec(size_t i,
2452 const string& tn,
2453 const string& tn_regex)
2454 : priv_(new priv(i, tn, tn_regex))
2455{}
2456
2457/// Getter for the index of the parameter designated by this
2458/// specification.
2459///
2460/// @return the index of the parameter designated by this
2461/// specification.
2462size_t
2464{return priv_->index_;}
2465
2466/// Setter for the index of the parameter designated by this
2467/// specification.
2468///
2469/// @param i the new index to set.
2470void
2472{priv_->index_ = i;}
2473
2474/// Getter for the type name of the parameter designated by this specification.
2475///
2476/// @return the type name of the parameter.
2477const string&
2480
2481/// Setter for the type name of the parameter designated by this
2482/// specification.
2483///
2484/// @param tn new parameter type name to set.
2485void
2487{priv_->type_name_ = tn;}
2488
2489/// Getter for the regular expression that defines a set of type names
2490/// for the parameter designated by this specification.
2491///
2492/// Note that at evaluation time, this regular expression is taken in
2493/// account only if the name of the parameter as returned by
2494/// function_suppression::parameter_spec::get_parameter_type_name() is
2495/// empty.
2496///
2497/// @return the regular expression or the parameter type name.
2498const string&
2500{return priv_->type_name_regex_str_;}
2501
2502/// Setter for the regular expression that defines a set of type names
2503/// for the parameter designated by this specification.
2504///
2505/// Note that at evaluation time, this regular expression is taken in
2506/// account only if the name of the parameter as returned by
2507/// function_suppression::parameter_spec::get_parameter_type_name() is
2508/// empty.
2509///
2510/// @param type_name_regex_str the new type name regular expression to
2511/// set.
2512void
2514(const string& type_name_regex_str)
2515{priv_->type_name_regex_str_ = type_name_regex_str;}
2516
2517/// Default constructor for the @ref function_suppression type.
2518///
2519/// It defines no suppression for now. Suppressions have to be
2520/// specified by using the various accessors of the @ref
2521/// function_suppression type.
2523 : suppression_base(/*label=*/""), priv_(new priv)
2524{}
2525
2526/// Constructor for the @ref function_suppression type.
2527///
2528/// @param label an informative text string that the evalution code
2529/// might use to designate this function suppression specification in
2530/// error messages. This parameter might be empty, in which case it's
2531/// ignored at evaluation time.
2532///
2533/// @param the name of the function the user wants the current
2534/// specification to designate. This parameter might be empty, in
2535/// which case it's ignored at evaluation time.
2536///
2537/// @param nr if @p name is empty this parameter is a regular
2538/// expression for a family of names of functions the user wants the
2539/// current specification to designate. If @p name is not empty, this
2540/// parameter is ignored at specification evaluation time. This
2541/// parameter might be empty, in which case it's ignored at evaluation
2542/// time.
2543///
2544/// @param ret_tn the name of the return type of the function the user
2545/// wants this specification to designate. This parameter might be
2546/// empty, in which case it's ignored at evaluation time.
2547///
2548/// @param ret_tr if @p ret_tn is empty, then this is a regular
2549/// expression for a family of return type names for functions the
2550/// user wants the current specification to designate. If @p ret_tn
2551/// is not empty, then this parameter is ignored at specification
2552/// evaluation time. This parameter might be empty, in which case
2553/// it's ignored at evaluation time.
2554///
2555/// @param ps a vector of parameter specifications to specify
2556/// properties of the parameters of the functions the user wants this
2557/// specification to designate. This parameter might be empty, in
2558/// which case it's ignored at evaluation time.
2559///
2560/// @param sym_n the name of symbol of the function the user wants
2561/// this specification to designate. This parameter might be empty,
2562/// in which case it's ignored at evaluation time.
2563///
2564/// @param sym_nr if the parameter @p sym_n is empty, then this
2565/// parameter is a regular expression for a family of names of symbols
2566/// of functions the user wants this specification to designate. If
2567/// the parameter @p sym_n is not empty, then this parameter is
2568/// ignored at specification evaluation time. This parameter might be
2569/// empty, in which case it's ignored at evaluation time.
2570///
2571/// @param sym_v the name of the version of the symbol of the function
2572/// the user wants this specification to designate. This parameter
2573/// might be empty, in which case it's ignored at evaluation time.
2574///
2575/// @param sym_vr if the parameter @p sym_v is empty, then this
2576/// parameter is a regular expression for a family of versions of
2577/// symbols of functions the user wants the current specification to
2578/// designate. If the parameter @p sym_v is non empty, then this
2579/// parameter is ignored. This parameter might be empty, in which
2580/// case it's ignored at evaluation time.
2582 const string& name,
2583 const string& nr,
2584 const string& ret_tn,
2585 const string& ret_tr,
2587 const string& sym_n,
2588 const string& sym_nr,
2589 const string& sym_v,
2590 const string& sym_vr)
2591 : suppression_base(label),
2592 priv_(new priv(name, nr, ret_tn, ret_tr, ps,
2593 sym_n, sym_nr, sym_v, sym_vr))
2594{}
2595
2596function_suppression::~function_suppression()
2597{}
2598
2599/// Parses a string containing the content of the "change-kind"
2600/// property and returns the an instance of @ref
2601/// function_suppression::change_kind as a result.
2602///
2603/// @param s the string to parse.
2604///
2605/// @return the resulting @ref function_suppression::change_kind.
2608{
2609 if (s == "function-subtype-change")
2611 else if (s == "added-function")
2613 else if (s == "deleted-function")
2615 else if (s == "all")
2616 return ALL_CHANGE_KIND;
2617 else
2618 return UNDEFINED_CHANGE_KIND;
2619}
2620
2621/// Getter of the "change-kind" property.
2622///
2623/// @param returnthe "change-kind" property.
2626{return priv_->change_kind_;}
2627
2628/// Setter of the "change-kind" property.
2629///
2630/// @param k the new value of the change_kind property.
2631void
2633{priv_->change_kind_ = k;}
2634
2635/// Getter for the name of the function the user wants the current
2636/// specification to designate. This might be empty, in which case
2637/// it's ignored at evaluation time.
2638///
2639/// @return the name of the function.
2640const string&
2642{return priv_->name_;}
2643
2644/// Setter for the name of the function the user wants the current
2645/// specification to designate. This might be empty, in which case
2646/// it's ignored at evaluation time.
2647///
2648/// @param n the new function name to set.
2649void
2651{priv_->name_ = n;}
2652
2653/// Getter for a regular expression for a family of names of functions
2654/// the user wants the current specification to designate.
2655///
2656/// @return the regular expression for the possible names of the
2657/// function(s).
2658const string&
2660{return priv_->name_regex_str_;}
2661
2662/// Setter for a regular expression for a family of names of functions
2663/// the user wants the current specification to designate.
2664///
2665/// @param r the new the regular expression for the possible names of
2666/// the function(s).
2667void
2669{priv_->name_regex_str_ = r;}
2670
2671/// Getter for a regular expression of a family of names of functions
2672/// the user wants the current specification to designate the negation
2673/// of.
2674///
2675/// @return the regular expression for the possible names of the
2676/// function(s).
2677const string&
2679{return priv_->name_not_regex_str_;}
2680
2681/// Setter for a regular expression for a family of names of functions
2682/// the user wants the current specification to designate the negation
2683/// of.
2684///
2685/// @param r the new the regular expression for the possible names of
2686/// the function(s).
2687void
2689{priv_->name_not_regex_str_ = r;}
2690
2691/// Getter for the name of the return type of the function the user
2692/// wants this specification to designate. This property might be
2693/// empty, in which case it's ignored at evaluation time.
2694///
2695/// @return the name of the return type of the function.
2696const string&
2698{return priv_->return_type_name_;}
2699
2700/// Setter for the name of the return type of the function the user
2701/// wants this specification to designate. This property might be
2702/// empty, in which case it's ignored at evaluation time.
2703///
2704/// @param tr the new name of the return type of the function to set.
2705void
2707{priv_->return_type_name_ = tr;}
2708
2709/// Getter for a regular expression for a family of return type names
2710/// for functions the user wants the current specification to
2711/// designate.
2712///
2713/// If the name of the return type of the function as returned by
2714/// function_suppression::get_return_type_name() is not empty, then
2715/// this property is ignored at specification evaluation time. This
2716/// property might be empty, in which case it's ignored at evaluation
2717/// time.
2718///
2719/// @return the regular expression for the possible names of the
2720/// return types of the function(s).
2721const string&
2723{return priv_->return_type_regex_str_;}
2724
2725/// Setter for a regular expression for a family of return type names
2726/// for functions the user wants the current specification to
2727/// designate.
2728///
2729/// If the name of the return type of the function as returned by
2730/// function_suppression::get_return_type_name() is not empty, then
2731/// this property is ignored at specification evaluation time. This
2732/// property might be empty, in which case it's ignored at evaluation
2733/// time.
2734///
2735/// @param r the new regular expression for the possible names of the
2736/// return types of the function(s) to set.
2737void
2739{priv_->return_type_regex_str_ = r;}
2740
2741/// Getter for a vector of parameter specifications to specify
2742/// properties of the parameters of the functions the user wants this
2743/// specification to designate.
2744///
2745/// This property might be empty, in which case it's ignored at
2746/// evaluation time.
2747///
2748/// @return the specifications of the parameters of the function(s).
2751{return priv_->parm_specs_;}
2752
2753/// Setter for a vector of parameter specifications to specify
2754/// properties of the parameters of the functions the user wants this
2755/// specification to designate.
2756///
2757/// This property might be empty, in which case it's ignored at
2758/// evaluation time.
2759///
2760/// @param p the new specifications of the parameters of the
2761/// function(s) to set.
2762void
2765
2766/// Append a specification of a parameter of the function specification.
2767///
2768/// @param p the parameter specification to add.
2769void
2771{priv_->parm_specs_.push_back(p);}
2772
2773/// Getter for the name of symbol of the function the user wants this
2774/// specification to designate.
2775///
2776/// This property might be empty, in which case it's ignored at
2777/// evaluation time.
2778///
2779/// @return name of the symbol of the function.
2780const string&
2782{return priv_->symbol_name_;}
2783
2784/// Setter for the name of symbol of the function the user wants this
2785/// specification to designate.
2786///
2787/// This property might be empty, in which case it's ignored at
2788/// evaluation time.
2789///
2790/// @return name of the symbol of the function.
2791void
2793{priv_->symbol_name_ = n;}
2794
2795/// Getter for a regular expression for a family of names of symbols
2796/// of functions the user wants this specification to designate.
2797///
2798/// If the symbol name as returned by
2799/// function_suppression::get_symbol_name() is not empty, then this
2800/// property is ignored at specification evaluation time.
2801///
2802/// This property might be empty, in which case it's ignored at
2803/// evaluation time.
2804///
2805/// @return the regular expression for a family of names of symbols of
2806/// functions to designate.
2807const string&
2809{return priv_->symbol_name_regex_str_;}
2810
2811/// Setter for a regular expression for a family of names of symbols
2812/// of functions the user wants this specification to designate.
2813///
2814/// If the symbol name as returned by
2815/// function_suppression::get_symbol_name() is not empty, then this
2816/// property is ignored at specification evaluation time.
2817///
2818/// This property might be empty, in which case it's ignored at
2819/// evaluation time.
2820///
2821/// @param r the new regular expression for a family of names of
2822/// symbols of functions to set.
2823void
2825{priv_->symbol_name_regex_str_ = r;}
2826
2827/// Getter for a regular expression for a family of names of symbols
2828/// of functions the user wants this specification to designate.
2829///
2830/// If a symbol name is matched by this regular expression, then the
2831/// suppression specification will *NOT* suppress the symbol.
2832///
2833/// If the symbol name as returned by
2834/// function_suppression::get_symbol_name() is not empty, then this
2835/// property is ignored at specification evaluation time.
2836///
2837/// This property might be empty, in which case it's ignored at
2838/// evaluation time.
2839///
2840/// @return the regular expression string for a family of names of
2841/// symbols that is to be *NOT* suppressed by this suppression specification.
2842const string&
2844{return priv_->symbol_name_not_regex_str_;}
2845
2846/// Setter for a regular expression for a family of names of symbols
2847/// of functions the user wants this specification to designate.
2848///
2849/// If a symbol name is matched by this regular expression, then the
2850/// suppression specification will *NOT* suppress the symbol.
2851///
2852/// If the symbol name as returned by
2853/// function_suppression::get_symbol_name() is not empty, then this
2854/// property is ignored at specification evaluation time.
2855///
2856/// This property might be empty, in which case it's ignored at
2857/// evaluation time.
2858///
2859/// @param the new regular expression string for a family of names of
2860/// symbols that is to be *NOT* suppressed by this suppression
2861/// specification.
2862void
2864{priv_->symbol_name_not_regex_str_ = r;}
2865
2866/// Getter for the name of the version of the symbol of the function
2867/// the user wants this specification to designate.
2868///
2869/// This property might be empty, in which case it's ignored at
2870/// evaluation time.
2871///
2872/// @return the symbol version of the function.
2873const string&
2875{return priv_->symbol_version_;}
2876
2877/// Setter for the name of the version of the symbol of the function
2878/// the user wants this specification to designate.
2879///
2880/// This property might be empty, in which case it's ignored at
2881/// evaluation time.
2882///
2883/// @param v the new symbol version of the function.
2884void
2886{priv_->symbol_version_ = v;}
2887
2888/// Getter for a regular expression for a family of versions of
2889/// symbols of functions the user wants the current specification to
2890/// designate.
2891///
2892/// If the symbol version as returned by
2893/// function_suppression::get_symbol_version() is non empty, then this
2894/// property is ignored. This property might be empty, in which case
2895/// it's ignored at evaluation time.
2896///
2897/// @return the regular expression for the versions of symbols of
2898/// functions to designate.
2899const string&
2901{return priv_->symbol_version_regex_str_;}
2902
2903/// Setter for a regular expression for a family of versions of
2904/// symbols of functions the user wants the current specification to
2905/// designate.
2906///
2907/// If the symbol version as returned by
2908/// function_suppression::get_symbol_version() is non empty, then this
2909/// property is ignored. This property might be empty, in which case
2910/// it's ignored at evaluation time.
2911///
2912/// @param the new regular expression for the versions of symbols of
2913/// functions to designate.
2914void
2916{priv_->symbol_version_regex_str_ = r;}
2917
2918/// Getter for the "allow_other_aliases" property of the function
2919/// suppression specification.
2920///
2921/// @return the value of the "allow_other_aliases" property.
2922bool
2924{return priv_->allow_other_aliases_;}
2925
2926/// Setter for the "allow_other_aliases" property of the function
2927/// suppression specification.
2928///
2929/// @param f the new value of the property.
2930void
2932{priv_->allow_other_aliases_ = f;}
2933
2934/// Evaluate this suppression specification on a given diff node and
2935/// say if the diff node should be suppressed or not.
2936///
2937/// @param diff the diff node to evaluate this suppression
2938/// specification against.
2939///
2940/// @return true if @p diff should be suppressed.
2941bool
2943{
2945 if (!d)
2946 return false;
2947
2950 ABG_ASSERT(ff && sf);
2951
2952 return (suppresses_function(ff,
2954 diff->context())
2955 || suppresses_function(sf,
2957 diff->context()));
2958}
2959
2960/// Evaluate the current function suppression specification on a given
2961/// @ref function_decl and say if a report about a change involving this
2962/// @ref function_decl should be suppressed or not.
2963///
2964/// @param fn the @ref function_decl to evaluate this suppression
2965/// specification against.
2966///
2967/// @param k the kind of function change @p fn is supposed to have.
2968///
2969/// @param ctxt the context of the current diff.
2970///
2971/// @return true iff a report about a change involving the function @p
2972/// fn should be suppressed.
2973bool
2975 change_kind k,
2976 const diff_context_sptr ctxt) const
2977{
2978 if (!(get_change_kind() & k))
2979 return false;
2980
2981 // Check if the name and soname of the binaries match the current
2982 // suppr spec
2983 if (ctxt)
2984 {
2985 // Check if the name of the binaries match the current suppr spec
2986 if (!names_of_binaries_match(*this, *ctxt))
2988 return false;
2989
2990 // Check if the soname of the binaries match the current suppr spec
2991 if (!sonames_of_binaries_match(*this, *ctxt))
2993 return false;
2994 }
2995
2996 string fname = fn->get_qualified_name();
2997
2998 // Check if the "name" property matches.
2999 if (!get_name().empty())
3000 {
3001 if (get_name() != fn->get_qualified_name())
3002 return false;
3003
3005 && fn->get_symbol()
3006 && fn->get_symbol()->get_alias_from_name(fname))
3007 {
3008 // So we are in a case of a languages in which the symbol
3009 // name is the same as the function name and we want to
3010 // allow the removal of change reports on an aliased
3011 // function only if the suppression condition matches the
3012 // names of all aliases.
3013 string symbol_name;
3014 elf_symbol_sptr sym = fn->get_symbol();
3015 ABG_ASSERT(sym);
3016 symbol_name = sym->get_name();
3017 if (sym->has_aliases() && sym->get_alias_from_name(fname))
3018 {
3019 for (elf_symbol_sptr a = sym->get_next_alias();
3020 a && !a->is_main_symbol();
3021 a = a->get_next_alias())
3022 if (a->get_name() != symbol_name)
3023 // There is an alias which name is different from
3024 // the function (symbol) name given in the
3025 // suppression condition.
3026 return false;
3027 }
3028 }
3029 }
3030
3031 // check if the "name_regexp" property matches.
3032 const regex_t_sptr name_regex = priv_->get_name_regex();
3033 if (name_regex)
3034 {
3035 if (!regex::match(name_regex, fname))
3036 return false;
3037
3039 && fn->get_symbol()
3040 && fn->get_symbol()->get_alias_from_name(fname))
3041 {
3042 // So we are in a case of a languages in which the symbol
3043 // name is the same as the function name and we want to
3044 // allow the removal of change reports on an aliased
3045 // function only if the suppression condition matches *all*
3046 // the aliases.
3047 string symbol_name;
3048 elf_symbol_sptr sym = fn->get_symbol();
3049 ABG_ASSERT(sym);
3050 symbol_name = sym->get_name();
3051 if (sym->has_aliases())
3052 {
3053 for (elf_symbol_sptr a = sym->get_next_alias();
3054 a && !a->is_main_symbol();
3055 a = a->get_next_alias())
3056 if (!regex::match(name_regex, a->get_name()))
3057 return false;
3058 }
3059 }
3060 }
3061
3062 // check if the "name_not_regexp" property matches.
3063 const regex_t_sptr name_not_regex = priv_->get_name_not_regex();
3064 if (name_not_regex)
3065 {
3066 if (regex::match(name_not_regex, fname))
3067 return false;
3068
3070 && fn->get_symbol()
3071 && fn->get_symbol()->get_alias_from_name(fname))
3072 {
3073 // So we are in a case of a languages in which the symbol
3074 // name is the same as the function name and we want to
3075 // allow the removal of change reports on an aliased
3076 // function only if the suppression condition matches *all*
3077 // the aliases.
3078 string symbol_name;
3079 elf_symbol_sptr sym = fn->get_symbol();
3080 ABG_ASSERT(sym);
3081 symbol_name = sym->get_name();
3082 if (sym->has_aliases())
3083 {
3084 for (elf_symbol_sptr a = sym->get_next_alias();
3085 a && !a->is_main_symbol();
3086 a = a->get_next_alias())
3087 if (regex::match(name_regex, a->get_name()))
3088 return false;
3089 }
3090 }
3091 }
3092
3093 // Check if the "return_type_name" or "return_type_regexp"
3094 // properties matches.
3095
3096 string fn_return_type_name = fn->get_type()->get_return_type()
3097 ? static_cast<string>
3098 ((get_type_declaration(fn->get_type()->get_return_type())
3099 ->get_qualified_name()))
3100 : "";
3101
3102 if (!get_return_type_name().empty())
3103 {
3104 if (fn_return_type_name != get_return_type_name())
3105 return false;
3106 }
3107 else
3108 {
3109 const regex_t_sptr return_type_regex = priv_->get_return_type_regex();
3110 if (return_type_regex
3111 && !regex::match(return_type_regex, fn_return_type_name))
3112 return false;
3113 }
3114
3115 // Check if the "symbol_name", "symbol_name_regexp", and
3116 // "symbol_name_not_regexp" properties match.
3117 string fn_sym_name, fn_sym_version;
3118 elf_symbol_sptr sym = fn->get_symbol();
3119 if (sym)
3120 {
3121 fn_sym_name = sym->get_name();
3122 fn_sym_version = sym->get_version().str();
3123 }
3124
3125 if (sym && !get_symbol_name().empty())
3126 {
3127 if (fn_sym_name != get_symbol_name())
3128 return false;
3129
3130 if (sym && get_allow_other_aliases())
3131 {
3132 // In this case, we want to allow the suppression of change
3133 // reports about an aliased symbol only if the suppression
3134 // condition matches the name of all aliases.
3135 if (sym->has_aliases())
3136 {
3137 for (elf_symbol_sptr a = sym->get_next_alias();
3138 a && !a->is_main_symbol();
3139 a = a->get_next_alias())
3140 if (a->get_name() != fn_sym_name)
3141 return false;
3142 }
3143 }
3144 }
3145 else if (sym)
3146 {
3147 const regex_t_sptr symbol_name_regex = priv_->get_symbol_name_regex();
3148 if (symbol_name_regex && !regex::match(symbol_name_regex, fn_sym_name))
3149 return false;
3150
3151 const regex_t_sptr symbol_name_not_regex =
3152 priv_->get_symbol_name_not_regex();
3153 if (symbol_name_not_regex
3154 && regex::match(symbol_name_not_regex, fn_sym_name))
3155 return false;
3156
3158 {
3159 // In this case, we want to allow the suppression of change
3160 // reports about an aliased symbol only if the suppression
3161 // condition matches the name of all aliases.
3162 if (sym->has_aliases())
3163 {
3164 for (elf_symbol_sptr a = sym->get_next_alias();
3165 a && !a->is_main_symbol();
3166 a = a->get_next_alias())
3167 {
3168 if (symbol_name_regex
3169 && !regex::match(symbol_name_regex, a->get_name()))
3170 return false;
3171
3172 if (symbol_name_not_regex
3173 && regex::match(symbol_name_not_regex, a->get_name()))
3174 return false;
3175 }
3176 }
3177 }
3178 }
3179
3180 // Check if the "symbol_version" and "symbol_version_regexp"
3181 // properties match.
3182 if (sym && !get_symbol_version().empty())
3183 {
3184 if (fn_sym_version != get_symbol_version())
3185 return false;
3186 }
3187 else if (sym)
3188 {
3189 const regex_t_sptr symbol_version_regex =
3190 priv_->get_symbol_version_regex();
3191 if (symbol_version_regex
3192 && !regex::match(symbol_version_regex, fn_sym_version))
3193 return false;
3194 }
3195
3196 // Check the 'parameter' property.
3197 if (!get_parameter_specs().empty())
3198 {
3199 function_type_sptr fn_type = fn->get_type();
3200 type_base_sptr parm_type;
3201
3202 for (parameter_specs_type::const_iterator p =
3203 get_parameter_specs().begin();
3204 p != get_parameter_specs().end();
3205 ++p)
3206 {
3207 size_t index = (*p)->get_index();
3209 fn_type->get_parm_at_index_from_first_non_implicit_parm(index);
3210 if (!fn_parm)
3211 return false;
3212
3213 string fn_parm_type_qualified_name;
3214 if (fn_parm)
3215 {
3216 parm_type = fn_parm->get_type();
3217 fn_parm_type_qualified_name =
3219 }
3220
3221 const string& tn = (*p)->get_parameter_type_name();
3222 if (!tn.empty())
3223 {
3224 if (tn != fn_parm_type_qualified_name)
3225 return false;
3226 }
3227 else
3228 {
3229 const regex_t_sptr parm_type_name_regex =
3230 (*p)->priv_->get_type_name_regex();
3231 if (parm_type_name_regex)
3232 {
3233 if (!regex::match(parm_type_name_regex,
3234 fn_parm_type_qualified_name))
3235 return false;
3236 }
3237 }
3238 }
3239 }
3240
3241 return true;
3242}
3243
3244/// Evaluate the current function suppression specification on a given
3245/// @ref function_decl and say if a report about a change involving this
3246/// @ref function_decl should be suppressed or not.
3247///
3248/// @param fn the @ref function_decl to evaluate this suppression
3249/// specification against.
3250///
3251/// @param k the kind of function change @p fn is supposed to have.
3252///
3253/// @param ctxt the context of the current diff.
3254///
3255/// @return true iff a report about a change involving the function @p
3256/// fn should be suppressed.
3257bool
3259 change_kind k,
3260 const diff_context_sptr ctxt) const
3261{return suppresses_function(fn.get(), k, ctxt);}
3262
3263/// Evaluate the current function suppression specification on a given
3264/// @ref elf_symbol and say if a report about a change involving this
3265/// @ref elf_symbol should be suppressed or not.
3266///
3267/// @param sym the @ref elf_symbol to evaluate this suppression
3268/// specification against.
3269///
3270/// @param k the kind of function change @p sym is supposed to have.
3271///
3272/// @param ctxt the context of the current diff.
3273///
3274/// @return true iff a report about a change involving the symbol @p
3275/// sym should be suppressed.
3276bool
3278 change_kind k,
3279 const diff_context_sptr ctxt)
3280{
3281 if (!sym)
3282 return false;
3283
3284 if (!(get_change_kind() & k))
3285 return false;
3286
3287 if (!sym->is_function())
3288 return false;
3289
3292
3293 // Check if the name and soname of the binaries match the current
3294 // suppr spect
3295 if (ctxt)
3296 {
3297 // Check if the name of the binaries match the current
3298 // suppr spect
3299 if (!names_of_binaries_match(*this, *ctxt))
3301 return false;
3302
3303 // Check if the soname of the binaries match the current
3304 // suppr spect
3305 if (!sonames_of_binaries_match(*this, *ctxt))
3307 return false;
3308 }
3309
3310 string sym_name = sym->get_name(), sym_version = sym->get_version().str();
3311 bool no_symbol_name = false, no_symbol_version = false;
3312
3313 // Consider the symbol name.
3314 if (!get_symbol_name().empty())
3315 {
3316 if (sym_name != get_symbol_name())
3317 return false;
3318 }
3319 else if (!get_symbol_name_regex_str().empty())
3320 {
3321 const regex_t_sptr symbol_name_regex = priv_->get_symbol_name_regex();
3322 if (symbol_name_regex && !regex::match(symbol_name_regex, sym_name))
3323 return false;
3324 }
3325 else
3326 no_symbol_name = true;
3327
3328 // Consider the symbol version
3329 if (!get_symbol_version().empty())
3330 {
3331 if (sym_version != get_symbol_version())
3332 return false;
3333 }
3334 else if (!get_symbol_version_regex_str().empty())
3335 {
3336 const regex_t_sptr symbol_version_regex =
3337 priv_->get_symbol_version_regex();
3338 if (symbol_version_regex
3339 && !regex::match(symbol_version_regex, sym_version))
3340 return false;
3341 }
3342 else
3343 no_symbol_version = true;
3344
3345 if (no_symbol_name && no_symbol_version)
3346 return false;
3347
3348 return true;
3349}
3350
3351/// Evaluate the current function suppression specification on a given
3352/// @ref elf_symbol and say if a report about a change involving this
3353/// @ref elf_symbol should be suppressed or not.
3354///
3355/// @param sym the @ref elf_symbol to evaluate this suppression
3356/// specification against.
3357///
3358/// @param k the kind of function change @p sym is supposed to have.
3359///
3360/// @param ctxt the context of the current diff.
3361///
3362/// @return true iff a report about a change involving the symbol @p
3363/// sym should be suppressed.
3364bool
3369
3370/// Test if an instance of @ref suppression is an instance of @ref
3371/// function_suppression.
3372///
3373/// @param suppr the instance of @ref suppression to test for.
3374///
3375/// @return if @p suppr is an instance of @ref function_suppression, then
3376/// return the sub-object of the @p suppr of type @ref
3377/// function_suppression, otherwise return a nil pointer.
3380{return dynamic_pointer_cast<function_suppression>(suppr);}
3381
3382/// The bitwise 'and' operator for the enum @ref
3383/// function_suppression::change_kind.
3384///
3385/// @param l the first operand of the 'and' operator.
3386///
3387/// @param r the second operand of the 'and' operator.
3388///
3389/// @return the result of 'and' operation on @p l and @p r.
3393{
3394 return static_cast<function_suppression::change_kind>
3395 (static_cast<unsigned>(l) & static_cast<unsigned>(r));
3396}
3397
3398/// The bitwise 'or' operator for the enum @ref
3399/// function_suppression::change_kind.
3400///
3401/// @param l the first operand of the 'or' operator.
3402///
3403/// @param r the second operand of the 'or' operator.
3404///
3405/// @return the result of 'or' operation on @p l and @p r.
3409{
3410 return static_cast<function_suppression::change_kind>
3411 (static_cast<unsigned>(l) | static_cast<unsigned>(r));
3412}
3413
3414/// Test if a variable suppression matches a variable denoted by its name.
3415///
3416/// @param s the variable suppression to consider.
3417///
3418/// @param var_name the name of the variable to consider.
3419///
3420/// @return true if the variable is matches by the suppression
3421/// specification.
3422bool
3424 const string& var_name)
3425{
3426 if (regex_t_sptr regexp = s.priv_->get_name_regex())
3427 {
3428 if (!regex::match(regexp, var_name))
3429 return false;
3430 }
3431 else if (regex_t_sptr regexp = s.priv_->get_name_not_regex())
3432 {
3433 if (regex::match(regexp, var_name))
3434 return false;
3435 }
3436 else if (s.priv_->name_.empty())
3437 return false;
3438 else // if (!s.priv_->name_.empty())
3439 {
3440 if (s.priv_->name_ != var_name)
3441 return false;
3442 }
3443
3444 return true;
3445}
3446
3447/// Test if a variable suppression matches a variable denoted by its
3448/// symbol name.
3449///
3450/// @param s the variable suppression to consider.
3451///
3452/// @param var_linkage_name the name of the variable to consider.
3453///
3454/// @return true if the variable is matches by the suppression
3455/// specification.
3456bool
3458 const string& var_linkage_name)
3459{
3460 if (regex_t_sptr regexp = s.priv_->get_symbol_name_regex())
3461 {
3462 if (!regex::match(regexp, var_linkage_name))
3463 return false;
3464 }
3465 else if (regex_t_sptr regexp =
3466 s.priv_->get_symbol_name_not_regex())
3467 {
3468 if (regex::match(regexp, var_linkage_name))
3469 return false;
3470 }
3471 else if (s.priv_->symbol_name_.empty())
3472 return false;
3473 else // if (!s.priv_->symbol_name_.empty())
3474 {
3475 if (s.priv_->symbol_name_ != var_linkage_name)
3476 return false;
3477 }
3478
3479 return true;
3480}
3481
3482/// Test if a type suppression matches a type designated by its fully
3483/// qualified name.
3484///
3485/// @param s the type suppression to consider.
3486///
3487/// @param type_name the name of the type to consider.
3488///
3489/// @return true iff the suppression s matches the type denoted by
3490/// name @p type_name.
3491bool
3493 const string& type_name)
3494{
3495 if (regex_t_sptr regexp = s.priv_->get_type_name_regex())
3496 {
3497 if (!regex::match(regexp, type_name))
3498 return false;
3499 }
3500 else if (!s.get_type_name().empty())
3501 {
3502 if (s.get_type_name() != type_name)
3503 return false;
3504 }
3505 else
3506 return false;
3507
3508 return true;
3509}
3510
3511/// Parse a string containing a parameter spec, build an instance of
3512/// function_suppression::parameter_spec from it and return a pointer
3513/// to that object.
3514///
3515/// @return a shared pointer pointer to the newly built instance of
3516/// function_suppression::parameter_spec. If the parameter
3517/// specification could not be parsed, return a nil object.
3519read_parameter_spec_from_string(const string& str)
3520{
3521 string::size_type cur = 0;
3523
3524 // skip leading white spaces.
3525 for (; cur < str.size(); ++cur)
3526 if (!isspace(str[cur]))
3527 break;
3528
3529 // look for the parameter index
3530 string index_str;
3531 if (str[cur] == '\'')
3532 {
3533 ++cur;
3534 for (; cur < str.size(); ++cur)
3535 if (!isdigit(str[cur]))
3536 break;
3537 else
3538 index_str += str[cur];
3539 }
3540
3541 // skip white spaces.
3542 for (; cur < str.size(); ++cur)
3543 if (!isspace(str[cur]))
3544 break;
3545
3546 bool is_regex = false;
3547 if (str[cur] == '/')
3548 {
3549 is_regex = true;
3550 ++cur;
3551 }
3552
3553 // look for the type name (regex)
3554 string type_name;
3555 for (; cur < str.size(); ++cur)
3556 if (!isspace(str[cur]))
3557 {
3558 if (is_regex && str[cur] == '/')
3559 break;
3560 type_name += str[cur];
3561 }
3562
3563 if (is_regex && str[cur] == '/')
3564 ++cur;
3565
3566 if (!index_str.empty() || !type_name.empty())
3567 {
3568 std::string type_name_regex;
3569 if (is_regex)
3570 {
3571 type_name_regex = type_name;
3572 type_name.clear();
3573 }
3574 function_suppression::parameter_spec* p =
3575 new function_suppression::parameter_spec(atoi(index_str.c_str()),
3576 type_name, type_name_regex);
3577 result.reset(p);
3578 }
3579
3580 return result;
3581}
3582
3583/// Parse function suppression specification, build a resulting @ref
3584/// function_suppression type and return a shared pointer to that
3585/// object.
3586///
3587/// @return a shared pointer to the newly built @ref
3588/// function_suppression. If the function suppression specification
3589/// could not be parsed then a nil shared pointer is returned.
3591read_function_suppression(const ini::config::section& section)
3592{
3594
3595 if (section.get_name() != "suppress_function")
3596 return result;
3597
3598 static const char *const sufficient_props[] = {
3599 "label",
3600 "file_name_regexp",
3601 "file_name_not_regexp",
3602 "soname_regexp",
3603 "soname_not_regexp",
3604 "name",
3605 "name_regexp",
3606 "name_not_regexp",
3607 "parameter",
3608 "return_type_name",
3609 "return_type_regexp",
3610 "symbol_name",
3611 "symbol_name_regexp",
3612 "symbol_name_not_regexp",
3613 "symbol_version",
3614 "symbol_version_regexp",
3615 };
3616 if (!check_sufficient_props(sufficient_props,
3617 sizeof(sufficient_props)/sizeof(char*),
3618 section))
3619 return result;
3620
3621 ini::simple_property_sptr drop_artifact =
3622 is_simple_property(section.find_property("drop_artifact"));
3623 if (!drop_artifact)
3624 drop_artifact = is_simple_property(section.find_property("drop"));
3625
3626 string drop_artifact_str = drop_artifact
3627 ? drop_artifact->get_value()->as_string()
3628 : "";
3629
3630 ini::simple_property_sptr change_kind_prop =
3631 is_simple_property(section.find_property("change_kind"));
3632 string change_kind_str = change_kind_prop
3633 ? change_kind_prop->get_value()->as_string()
3634 : "";
3635
3636 ini::simple_property_sptr label_prop =
3637 is_simple_property(section.find_property("label"));
3638 string label_str = label_prop
3639 ? label_prop->get_value()->as_string()
3640 : "";
3641
3642 ini::simple_property_sptr file_name_regex_prop =
3643 is_simple_property(section.find_property("file_name_regexp"));
3644 string file_name_regex_str =
3645 file_name_regex_prop ? file_name_regex_prop->get_value()->as_string() : "";
3646
3647 ini::simple_property_sptr file_name_not_regex_prop =
3648 is_simple_property(section.find_property("file_name_not_regexp"));
3649 string file_name_not_regex_str =
3650 file_name_not_regex_prop
3651 ? file_name_not_regex_prop->get_value()->as_string()
3652 : "";
3653
3654 ini::simple_property_sptr soname_regex_prop =
3655 is_simple_property(section.find_property("soname_regexp"));
3656 string soname_regex_str =
3657 soname_regex_prop ? soname_regex_prop->get_value()->as_string() : "";
3658
3659 ini::simple_property_sptr soname_not_regex_prop =
3660 is_simple_property(section.find_property("soname_not_regexp"));
3661 string soname_not_regex_str =
3662 soname_not_regex_prop
3663 ? soname_not_regex_prop->get_value()->as_string()
3664 : "";
3665
3666 ini::simple_property_sptr name_prop =
3667 is_simple_property(section.find_property("name"));
3668 string name = name_prop
3669 ? name_prop->get_value()->as_string()
3670 : "";
3671
3672 ini::simple_property_sptr name_regex_prop =
3673 is_simple_property(section.find_property("name_regexp"));
3674 string name_regex_str = name_regex_prop
3675 ? name_regex_prop->get_value()->as_string()
3676 : "";
3677
3678 ini::simple_property_sptr name_not_regex_prop =
3679 is_simple_property(section.find_property("name_not_regexp"));
3680 string name_not_regex_str = name_not_regex_prop
3681 ? name_not_regex_prop->get_value()->as_string()
3682 : "";
3683
3684 ini::simple_property_sptr return_type_name_prop =
3685 is_simple_property(section.find_property("return_type_name"));
3686 string return_type_name = return_type_name_prop
3687 ? return_type_name_prop->get_value()->as_string()
3688 : "";
3689
3690 ini::simple_property_sptr return_type_regex_prop =
3691 is_simple_property(section.find_property("return_type_regexp"));
3692 string return_type_regex_str = return_type_regex_prop
3693 ? return_type_regex_prop->get_value()->as_string()
3694 : "";
3695
3696 ini::simple_property_sptr sym_name_prop =
3697 is_simple_property(section.find_property("symbol_name"));
3698 string sym_name = sym_name_prop
3699 ? sym_name_prop->get_value()->as_string()
3700 : "";
3701
3702 ini::simple_property_sptr sym_name_regex_prop =
3703 is_simple_property(section.find_property("symbol_name_regexp"));
3704 string sym_name_regex_str = sym_name_regex_prop
3705 ? sym_name_regex_prop->get_value()->as_string()
3706 : "";
3707
3708 ini::simple_property_sptr sym_name_not_regex_prop =
3709 is_simple_property(section.find_property("symbol_name_not_regexp"));
3710 string sym_name_not_regex_str = sym_name_not_regex_prop
3711 ? sym_name_not_regex_prop->get_value()->as_string()
3712 : "";
3713
3714 ini::simple_property_sptr sym_ver_prop =
3715 is_simple_property(section.find_property("symbol_version"));
3716 string sym_version = sym_ver_prop
3717 ? sym_ver_prop->get_value()->as_string()
3718 : "";
3719
3720 ini::simple_property_sptr sym_ver_regex_prop =
3721 is_simple_property(section.find_property("symbol_version_regexp"));
3722 string sym_ver_regex_str = sym_ver_regex_prop
3723 ? sym_ver_regex_prop->get_value()->as_string()
3724 : "";
3725
3726 ini::simple_property_sptr allow_other_aliases_prop =
3727 is_simple_property(section.find_property("allow_other_aliases"));
3728 string allow_other_aliases = allow_other_aliases_prop
3729 ? allow_other_aliases_prop->get_value()->as_string()
3730 : "";
3731
3734 for (ini::config::properties_type::const_iterator p =
3735 section.get_properties().begin();
3736 p != section.get_properties().end();
3737 ++p)
3738 if ((*p)->get_name() == "parameter")
3739 {
3741 ABG_ASSERT(prop);
3742 if ((parm = read_parameter_spec_from_string
3743 (prop->get_value()->as_string())))
3744 parms.push_back(parm);
3745 }
3746
3747 result.reset(new function_suppression(label_str,
3748 name,
3749 name_regex_str,
3750 return_type_name,
3751 return_type_regex_str,
3752 parms,
3753 sym_name,
3754 sym_name_regex_str,
3755 sym_version,
3756 sym_ver_regex_str));
3757
3758 if ((drop_artifact_str == "yes" || drop_artifact_str == "true")
3759 && (!name.empty()
3760 || !name_regex_str.empty()
3761 || !name_not_regex_str.empty()
3762 || !sym_name.empty()
3763 || !sym_name_regex_str.empty()
3764 || !sym_name_not_regex_str.empty()))
3765 result->set_drops_artifact_from_ir(true);
3766
3767 if (!change_kind_str.empty())
3768 result->set_change_kind
3769 (function_suppression::parse_change_kind(change_kind_str));
3770
3771 if (!allow_other_aliases.empty())
3772 result->set_allow_other_aliases(allow_other_aliases == "yes"
3773 || allow_other_aliases == "true");
3774
3775 if (!name_not_regex_str.empty())
3776 result->set_name_not_regex_str(name_not_regex_str);
3777
3778 if (!sym_name_not_regex_str.empty())
3779 result->set_symbol_name_not_regex_str(sym_name_not_regex_str);
3780
3781 if (!file_name_regex_str.empty())
3782 result->set_file_name_regex_str(file_name_regex_str);
3783
3784 if (!file_name_not_regex_str.empty())
3785 result->set_file_name_not_regex_str(file_name_not_regex_str);
3786
3787 if (!soname_regex_str.empty())
3788 result->set_soname_regex_str(soname_regex_str);
3789
3790 if (!soname_not_regex_str.empty())
3791 result->set_soname_not_regex_str(soname_not_regex_str);
3792
3793 return result;
3794}
3795
3796// </function_suppression stuff>
3797
3798// <variable_suppression stuff>
3799
3800/// Constructor for the @ref variable_suppression type.
3801///
3802/// @param label an informative text string that the evalution code
3803/// might use to designate this variable suppression specification in
3804/// error messages. This parameter might be empty, in which case it's
3805/// ignored at evaluation time.
3806///
3807/// @param name the name of the variable the user wants the current
3808/// specification to designate. This parameter might be empty, in
3809/// which case it's ignored at evaluation time.
3810///
3811/// @param name_regex_str if @p name is empty, this parameter is a
3812/// regular expression for a family of names of variables the user
3813/// wants the current specification to designate. If @p name is not
3814/// empty, then this parameter is ignored at evaluation time. This
3815/// parameter might be empty, in which case it's ignored at evaluation
3816/// time.
3817///
3818/// @param symbol_name the name of the symbol of the variable the user
3819/// wants the current specification to designate. This parameter
3820/// might be empty, in which case it's ignored at evaluation time.
3821///
3822/// @param symbol_name_str if @p symbol_name is empty, this parameter
3823/// is a regular expression for a family of names of symbols of
3824/// variables the user wants the current specification to designate.
3825/// If @p symbol_name is not empty, then this parameter is ignored at
3826/// evaluation time. This parameter might be empty, in which case
3827/// it's ignored at evaluation time.
3828///
3829/// @param symbol_version the version of the symbol of the variable
3830/// the user wants the current specification to designate. This
3831/// parameter might be empty, in which case it's ignored at evaluation
3832/// time.
3833///
3834/// @param symbol_version_regex if @p symbol_version is empty, then
3835/// this parameter is a regular expression for a family of versions of
3836/// symbol for the variables the user wants the current specification
3837/// to designate. If @p symbol_version is not empty, then this
3838/// parameter is ignored at evaluation time. This parameter might be
3839/// empty, in which case it's ignored at evaluation time.
3840///
3841/// @param type_name the name of the type of the variable the user
3842/// wants the current specification to designate. This parameter
3843/// might be empty, in which case it's ignored at evaluation time.
3844///
3845/// @param type_name_regex_str if @p type_name is empty, then this
3846/// parameter is a regular expression for a family of type names of
3847/// variables the user wants the current specification to designate.
3848/// If @p type_name is not empty, then this parameter is ignored at
3849/// evluation time. This parameter might be empty, in which case it's
3850/// ignored at evaluation time.
3852 const string& name,
3853 const string& name_regex_str,
3854 const string& symbol_name,
3855 const string& symbol_name_regex_str,
3856 const string& symbol_version,
3857 const string& symbol_version_regex,
3858 const string& type_name,
3859 const string& type_name_regex_str)
3860 : suppression_base(label),
3861 priv_(new priv(name, name_regex_str,
3862 symbol_name, symbol_name_regex_str,
3863 symbol_version, symbol_version_regex,
3864 type_name, type_name_regex_str))
3865{}
3866
3867/// Virtual destructor for the @erf variable_suppression type.
3868/// variable_suppression type.
3871
3872/// Parses a string containing the content of the "change-kind"
3873/// property and returns the an instance of @ref
3874/// variable_suppression::change_kind as a result.
3875///
3876/// @param s the string to parse.
3877///
3878/// @return the resulting @ref variable_suppression::change_kind.
3881{
3882 if (s == "variable-subtype-change")
3884 else if (s == "added-variable")
3886 else if (s == "deleted-variable")
3888 else if (s == "all")
3889 return ALL_CHANGE_KIND;
3890 else
3891 return UNDEFINED_CHANGE_KIND;
3892}
3893
3894/// Getter of the "change_king" property.
3895///
3896/// @return the value of the "change_kind" property.
3899{return priv_->change_kind_;}
3900
3901/// Setter of the "change_kind" property.
3902///
3903/// @param k the new value of of the change_kind.
3904void
3906{priv_->change_kind_ = k;}
3907
3908/// Getter for the name of the variable the user wants the current
3909/// specification to designate. This property might be empty, in
3910/// which case it's ignored at evaluation time.
3911///
3912/// @return the name of the variable.
3913const string&
3915{return priv_->name_;}
3916
3917/// Setter for the name of the variable the user wants the current
3918/// specification to designate. This property might be empty, in
3919/// which case it's ignored at evaluation time.
3920///
3921/// @param n the new name of the variable to set.
3922void
3924{priv_->name_ = n;}
3925
3926/// Getter for the regular expression for a family of names of
3927/// variables the user wants the current specification to designate.
3928/// If the variable name as returned by
3929/// variable_suppression::get_name() is not empty, then this property
3930/// is ignored at evaluation time. This property might be empty, in
3931/// which case it's ignored at evaluation time.
3932///
3933/// @return the regular expression for the variable name.
3934const string&
3936{return priv_->name_regex_str_;}
3937
3938/// Setter for the regular expression for a family of names of
3939/// variables the user wants the current specification to designate.
3940/// If the variable name as returned by
3941/// variable_suppression::get_name() is not empty, then this property
3942/// is ignored at evaluation time. This property might be empty, in
3943/// which case it's ignored at evaluation time.
3944///
3945/// @param r the new regular expression for the variable name.
3946void
3948{priv_->name_regex_str_ = r;}
3949
3950/// Getter for the "name_not_regexp" property of the specification.
3951///
3952/// @return the value of the "name_not_regexp" property.
3953const string&
3955{return priv_->name_not_regex_str_;}
3956
3957/// Setter for the "name_not_regexp" property of the specification.
3958///
3959/// @param r the new value of the "name_not_regexp" property.
3960void
3962{priv_->name_not_regex_str_ = r;}
3963
3964/// Getter for the name of the symbol of the variable the user wants
3965/// the current specification to designate.
3966///
3967/// This property might be empty, in which case it is ignored at
3968/// evaluation time.
3969///
3970/// @return the name of the symbol of the variable.
3971const string&
3973{return priv_->symbol_name_;}
3974
3975/// Setter for the name of the symbol of the variable the user wants
3976/// the current specification to designate.
3977///
3978/// This property might be empty, in which case it is ignored at
3979/// evaluation time.
3980///
3981/// @param n the new name of the symbol of the variable.
3982void
3984{priv_->symbol_name_ = n;}
3985
3986/// Getter of the regular expression for a family of symbol names of
3987/// the variables this specification is about to designate.
3988///
3989/// This property might be empty, in which case it's ignored at
3990/// evaluation time. Otherwise, it is taken in account iff the
3991/// property returned by variable_suppression::get_symbol_name() is
3992/// empty.
3993///
3994/// @return the regular expression for a symbol name of the variable.
3995const string&
3997{return priv_->symbol_name_regex_str_;}
3998
3999/// Setter of the regular expression for a family of symbol names of
4000/// the variables this specification is about to designate.
4001///
4002/// This property might be empty, in which case it's ignored at
4003/// evaluation time. Otherwise, it is taken in account iff the
4004/// property returned by variable_suppression::get_symbol_name() is
4005/// empty.
4006///
4007/// @param r the regular expression for a symbol name of the variable.
4008void
4010{priv_->symbol_name_regex_str_ = r;}
4011
4012/// Getter for a regular expression for a family of names of symbols
4013/// of variables the user wants this specification to designate.
4014///
4015/// If a symbol name is matched by this regular expression, then the
4016/// suppression specification will *NOT* suppress the symbol.
4017///
4018/// If the symbol name as returned by
4019/// variable_suppression::get_symbol_name() is not empty, then this
4020/// property is ignored at specification evaluation time.
4021///
4022/// This property might be empty, in which case it's ignored at
4023/// evaluation time.
4024///
4025/// @return the regular expression string for a family of names of
4026/// symbols that is to be *NOT* suppressed by this suppression specification.
4027const string&
4029{return priv_->symbol_name_not_regex_str_;}
4030
4031/// Setter for a regular expression for a family of names of symbols
4032/// of variables the user wants this specification to designate.
4033///
4034/// If a symbol name is matched by this regular expression, then the
4035/// suppression specification will *NOT* suppress the symbol.
4036///
4037/// If the symbol name as returned by
4038/// variable_suppression::get_symbol_name() is not empty, then this
4039/// property is ignored at specification evaluation time.
4040///
4041/// This property might be empty, in which case it's ignored at
4042/// evaluation time.
4043///
4044/// @param the new regular expression string for a family of names of
4045/// symbols that is to be *NOT* suppressed by this suppression
4046/// specification.
4047void
4049{priv_->symbol_name_not_regex_str_ = r;}
4050
4051/// Getter for the version of the symbol of the variable the user
4052/// wants the current specification to designate. This property might
4053/// be empty, in which case it's ignored at evaluation time.
4054///
4055/// @return the symbol version of the variable.
4056const string&
4058{return priv_->symbol_version_;}
4059
4060/// Setter for the version of the symbol of the variable the user
4061/// wants the current specification to designate. This property might
4062/// be empty, in which case it's ignored at evaluation time.
4063///
4064/// @return the new symbol version of the variable.
4065void
4067{priv_->symbol_version_ = v;}
4068
4069/// Getter of the regular expression for a family of versions of
4070/// symbol for the variables the user wants the current specification
4071/// to designate. If @p symbol_version is not empty, then this
4072/// property is ignored at evaluation time. This property might be
4073/// empty, in which case it's ignored at evaluation time.
4074///
4075/// @return the regular expression of the symbol version of the
4076/// variable.
4077const string&
4079{return priv_->symbol_version_regex_str_;}
4080
4081/// Setter of the regular expression for a family of versions of
4082/// symbol for the variables the user wants the current specification
4083/// to designate. If @p symbol_version is not empty, then this
4084/// property is ignored at evaluation time. This property might be
4085/// empty, in which case it's ignored at evaluation time.
4086///
4087/// @param v the new regular expression of the symbol version of the
4088/// variable.
4089void
4091{priv_->symbol_version_regex_str_ = r;}
4092
4093/// Getter for the name of the type of the variable the user wants the
4094/// current specification to designate.
4095///
4096/// This property might be empty, in which case it's ignored at
4097/// evaluation time.
4098///
4099/// @return the name of the variable type.
4100const string&
4102{return priv_->type_name_;}
4103
4104/// Setter for the name of the type of the variable the user wants the
4105/// current specification to designate.
4106///
4107/// This property might be empty, in which case it's ignored at
4108/// evaluation time.
4109///
4110/// @param n the new name of the variable type.
4111void
4113{priv_->type_name_ = n;}
4114
4115/// Getter for the regular expression for a family of type names of
4116/// variables the user wants the current specification to designate.
4117///
4118/// If the type name as returned by
4119/// variable_suppression::get_type_name() is not empty, then this
4120/// property is ignored at evaluation time. This property might be
4121/// empty, in which case it's ignored at evaluation time.
4122///
4123/// @return the regular expression of the variable type name.
4124const string&
4126{return priv_->type_name_regex_str_;}
4127
4128/// Setter for the regular expression for a family of type names of
4129/// variables the user wants the current specification to designate.
4130///
4131/// If the type name as returned by
4132/// variable_suppression::get_type_name() is not empty, then this
4133/// property is ignored at evaluation time. This property might be
4134/// empty, in which case it's ignored at evaluation time.
4135///
4136/// @param r the regular expression of the variable type name.
4137void
4139{priv_->type_name_regex_str_ = r;}
4140
4141/// Evaluate this suppression specification on a given diff node and
4142/// say if the diff node should be suppressed or not.
4143///
4144/// @param diff the diff node to evaluate this suppression
4145/// specification against.
4146///
4147/// @return true if @p diff should be suppressed.
4148bool
4150{
4151 const var_diff* d = is_var_diff(diff);
4152 if (!d)
4153 return false;
4154
4157
4158 ABG_ASSERT(fv && sv);
4159
4160 return (suppresses_variable(fv,
4162 diff->context())
4163 || suppresses_variable(sv,
4165 diff->context()));
4166}
4167
4168/// Evaluate the current variable suppression specification on a given
4169/// @ref var_decl and say if a report about a change involving this
4170/// @ref var_decl should be suppressed or not.
4171///
4172/// @param var the @ref var_decl to evaluate this suppression
4173/// specification against.
4174///
4175/// @param k the kind of variable change @p var is supposed to have.
4176///
4177/// @param ctxt the context of the current diff.
4178///
4179/// @return true iff a report about a change involving the variable @p
4180/// var should be suppressed.
4181bool
4183 change_kind k,
4184 const diff_context_sptr ctxt) const
4185{
4186 if (!(get_change_kind() & k))
4187 return false;
4188
4189 // Check if the name and soname of the binaries match
4190 if (ctxt)
4191 {
4192 // Check if the name of the binaries match the current
4193 // suppr spec
4194 if (!names_of_binaries_match(*this, *ctxt))
4196 return false;
4197
4198 // Check if the soname of the binaries match the current suppr
4199 // spec
4200 if (!sonames_of_binaries_match(*this, *ctxt))
4202 return false;
4203 }
4204
4205 string var_name = var->get_qualified_name();
4206
4207 // Check for "name" property match.
4208 if (!get_name().empty())
4209 {
4210 if (get_name() != var_name)
4211 return false;
4212 }
4213 else
4214 {
4215 // If the "name" property is empty, then consider checking for the
4216 // "name_regex" and "name_not_regex" properties match
4217 if (get_name().empty())
4218 {
4219 const regex_t_sptr name_regex = priv_->get_name_regex();
4220 if (name_regex && !regex::match(name_regex, var_name))
4221 return false;
4222
4223 const regex_t_sptr name_not_regex = priv_->get_name_not_regex();
4224 if (name_not_regex && regex::match(name_not_regex, var_name))
4225 return false;
4226 }
4227 }
4228
4229 // Check for the symbol_name, symbol_name_regex and
4230 // symbol_name_not_regex property match.
4231 string var_sym_name = var->get_symbol() ? var->get_symbol()->get_name() : "";
4232 if (!get_symbol_name().empty())
4233 {
4234 if (get_symbol_name() != var_sym_name)
4235 return false;
4236 }
4237 else
4238 {
4239 const regex_t_sptr sym_name_regex = priv_->get_symbol_name_regex();
4240 if (sym_name_regex && !regex::match(sym_name_regex, var_sym_name))
4241 return false;
4242
4243 const regex_t_sptr sym_name_not_regex =
4244 priv_->get_symbol_name_not_regex();
4245 if (sym_name_not_regex && regex::match(sym_name_not_regex, var_sym_name))
4246 return false;
4247 }
4248
4249 // Check for symbol_version and symbol_version_regexp property match
4250 string var_sym_version =
4251 var->get_symbol() ? var->get_symbol()->get_version().str() : "";
4252 if (!get_symbol_version().empty())
4253 {
4254 if (get_symbol_version() != var_sym_version)
4255 return false;
4256 }
4257 else
4258 {
4259 const regex_t_sptr symbol_version_regex =
4260 priv_->get_symbol_version_regex();
4261 if (symbol_version_regex
4262 && !regex::match(symbol_version_regex, var_sym_version))
4263 return false;
4264 }
4265
4266 // Check for the "type_name" and type_name_regex properties match.
4267 string var_type_name =
4269
4270 if (!get_type_name().empty())
4271 {
4272 if (get_type_name() != var_type_name)
4273 return false;
4274 }
4275 else
4276 {
4277 if (get_type_name().empty())
4278 {
4279 const regex_t_sptr type_name_regex = priv_->get_type_name_regex();
4280 if (type_name_regex && !regex::match(type_name_regex, var_type_name))
4281 return false;
4282 }
4283 }
4284
4285 return true;
4286}
4287
4288/// Evaluate the current variable suppression specification on a given
4289/// @ref var_decl and say if a report about a change involving this
4290/// @ref var_decl should be suppressed or not.
4291///
4292/// @param var the @ref var_decl to evaluate this suppression
4293/// specification against.
4294///
4295/// @param k the kind of variable change @p var is supposed to have.
4296///
4297/// @param ctxt the context of the current diff.
4298///
4299/// @return true iff a report about a change involving the variable @p
4300/// var should be suppressed.
4301bool
4303 change_kind k,
4304 const diff_context_sptr ctxt) const
4305{return suppresses_variable(var.get(), k, ctxt);}
4306
4307/// Evaluate the current variable suppression specification on a given
4308/// @ref elf_symbol and say if a report about a change involving this
4309/// @ref elf_symbol should be suppressed or not.
4310///
4311/// @param sym the @ref elf_symbol to evaluate this suppression
4312/// specification against.
4313///
4314/// @param k the kind of variable change @p sym is supposed to have.
4315///
4316/// @param ctxt the context of the current diff.
4317///
4318/// @return true iff a report about a change involving the symbol @p
4319/// sym should be suppressed.
4320bool
4322 change_kind k,
4323 const diff_context_sptr ctxt) const
4324{
4325 if (!sym)
4326 return false;
4327
4328 if (!(get_change_kind() & k))
4329 return false;
4330
4331 if (!sym->is_variable())
4332 return false;
4333
4336
4337 // Check if the name and soname of the binaries match the current
4338 // suppr spec.
4339 if (ctxt)
4340 {
4341 // Check if the name of the binaries match the current suppr
4342 // spec
4343 if (!names_of_binaries_match(*this, *ctxt))
4345 return false;
4346
4347 // Check if the soname of the binaries match the current suppr spec
4348 if (!sonames_of_binaries_match(*this, *ctxt))
4350 return false;
4351 }
4352
4353 string sym_name = sym->get_name(), sym_version = sym->get_version().str();
4354
4355 bool no_symbol_name = false, no_symbol_version = false;
4356
4357 // Consider the symbol name
4358 if (!get_name().empty())
4359 {
4360 if (get_name() != sym_name)
4361 return false;
4362 }
4363 else if (!get_symbol_name().empty())
4364 {
4365 if (get_symbol_name() != sym_name)
4366 return false;
4367 }
4368 else if (!get_symbol_name_regex_str().empty())
4369 {
4370 const regex_t_sptr sym_name_regex = priv_->get_symbol_name_regex();
4371 if (sym_name_regex && !regex::match(sym_name_regex, sym_name))
4372 return false;
4373 }
4374 else
4375 no_symbol_name = true;
4376
4377 // Consider the symbol version.
4378 if (!get_symbol_version().empty())
4379 {
4380 if (get_symbol_version() != sym_version)
4381 return false;
4382 }
4383 else if (!get_symbol_version_regex_str().empty())
4384 {
4385 const regex_t_sptr symbol_version_regex =
4386 priv_->get_symbol_version_regex();
4387 if (symbol_version_regex
4388 && !regex::match(symbol_version_regex, sym_version))
4389 return false;
4390 }
4391 else
4392 no_symbol_version = true;
4393
4394 if (no_symbol_name && no_symbol_version)
4395 return false;
4396
4397 return true;
4398}
4399
4400/// Evaluate the current variable suppression specification on a given
4401/// @ref elf_symbol and say if a report about a change involving this
4402/// @ref elf_symbol should be suppressed or not.
4403///
4404/// @param sym the @ref elf_symbol to evaluate this suppression
4405/// specification against.
4406///
4407/// @param k the kind of variable change @p sym is supposed to have.
4408///
4409/// @param ctxt the context of the current diff.
4410///
4411/// @return true iff a report about a change involving the symbol @p
4412/// sym should be suppressed.
4413bool
4418
4419/// Test if an instance of @ref suppression is an instance of @ref
4420/// variable_suppression.
4421///
4422/// @param suppr the instance of @ref suppression to test for.
4423///
4424/// @return if @p suppr is an instance of @ref variable_suppression, then
4425/// return the sub-object of the @p suppr of type @ref
4426/// variable_suppression, otherwise return a nil pointer.
4429{return dynamic_pointer_cast<variable_suppression>(s);}
4430
4431/// The bitwise 'and' operator for the enum @ref
4432/// variable_suppression::change_kind.
4433///
4434/// @param l the first operand of the 'and' operator.
4435///
4436/// @param r the second operand of the 'and' operator.
4437///
4438/// @return the result of 'and' operation on @p l and @p r.
4442{
4443 return static_cast<variable_suppression::change_kind>
4444 (static_cast<unsigned>(l) & static_cast<unsigned>(r));
4445}
4446
4447/// The bitwise 'or' operator for the enum @ref
4448/// variable_suppression::change_kind.
4449///
4450/// @param l the first operand of the 'or' operator.
4451///
4452/// @param r the second operand of the 'or' operator.
4453///
4454/// @return the result of 'or' operation on @p l and @p r.
4458{
4459 return static_cast<variable_suppression::change_kind>
4460 (static_cast<unsigned>(l) | static_cast<unsigned>(r));
4461}
4462
4463/// Parse variable suppression specification, build a resulting @ref
4464/// variable_suppression type and return a shared pointer to that
4465/// object.
4466///
4467/// @return a shared pointer to the newly built @ref
4468/// variable_suppression. If the variable suppression specification
4469/// could not be parsed then a nil shared pointer is returned.
4471read_variable_suppression(const ini::config::section& section)
4472{
4474
4475 if (section.get_name() != "suppress_variable")
4476 return result;
4477
4478 static const char *const sufficient_props[] = {
4479 "label",
4480 "file_name_regexp",
4481 "file_name_not_regexp",
4482 "soname_regexp",
4483 "soname_not_regexp",
4484 "name",
4485 "name_regexp",
4486 "name_not_regexp",
4487 "symbol_name",
4488 "symbol_name_regexp",
4489 "symbol_name_not_regexp",
4490 "symbol_version",
4491 "symbol_version_regexp",
4492 "type_name",
4493 "type_name_regexp",
4494 };
4495 if (!check_sufficient_props(sufficient_props,
4496 sizeof(sufficient_props)/sizeof(char*),
4497 section))
4498 return result;
4499
4500 ini::simple_property_sptr drop_artifact =
4501 is_simple_property(section.find_property("drop_artifact"));
4502 if (!drop_artifact)
4503 drop_artifact = is_simple_property(section.find_property("drop"));
4504
4505 string drop_artifact_str = drop_artifact
4506 ? drop_artifact->get_value()->as_string()
4507 : "";
4508
4509 ini::simple_property_sptr change_kind_prop =
4510 is_simple_property(section.find_property("change_kind"));
4511 string change_kind_str = change_kind_prop
4512 ? change_kind_prop->get_value()->as_string()
4513 : "";
4514
4515 ini::simple_property_sptr label_prop =
4516 is_simple_property(section.find_property("label"));
4517 string label_str = (label_prop
4518 ? label_prop->get_value()->as_string()
4519 : "");
4520
4521 ini::simple_property_sptr file_name_regex_prop =
4522 is_simple_property(section.find_property("file_name_regexp"));
4523 string file_name_regex_str =
4524 file_name_regex_prop ? file_name_regex_prop->get_value()->as_string() : "";
4525
4526 ini::simple_property_sptr file_name_not_regex_prop =
4527 is_simple_property(section.find_property("file_name_not_regexp"));
4528 string file_name_not_regex_str =
4529 file_name_not_regex_prop
4530 ? file_name_not_regex_prop->get_value()->as_string()
4531 : "";
4532
4533 ini::simple_property_sptr soname_regex_prop =
4534 is_simple_property(section.find_property("soname_regexp"));
4535 string soname_regex_str =
4536 soname_regex_prop ? soname_regex_prop->get_value()->as_string() : "";
4537
4538 ini::simple_property_sptr soname_not_regex_prop =
4539 is_simple_property(section.find_property("soname_not_regexp"));
4540 string soname_not_regex_str =
4541 soname_not_regex_prop
4542 ? soname_not_regex_prop->get_value()->as_string()
4543 : "";
4544
4545 ini::simple_property_sptr name_prop =
4546 is_simple_property(section.find_property("name"));
4547 string name_str = (name_prop
4548 ? name_prop->get_value()->as_string()
4549 : "");
4550
4551 ini::simple_property_sptr name_regex_prop =
4552 is_simple_property(section.find_property("name_regexp"));
4553 string name_regex_str = (name_regex_prop
4554 ? name_regex_prop->get_value()->as_string()
4555 : "");
4556
4557 ini::simple_property_sptr name_not_regex_prop =
4558 is_simple_property(section.find_property("name_not_regexp"));
4559 string name_not_regex_str = name_not_regex_prop
4560 ? name_not_regex_prop->get_value()->as_string()
4561 : "";
4562
4563 ini::simple_property_sptr sym_name_prop =
4564 is_simple_property(section.find_property("symbol_name"));
4565 string symbol_name = (sym_name_prop
4566 ? sym_name_prop->get_value()->as_string()
4567 : "");
4568
4569 ini::simple_property_sptr sym_name_regex_prop =
4570 is_simple_property(section.find_property("symbol_name_regexp"));
4571 string symbol_name_regex_str = sym_name_regex_prop
4572 ? sym_name_regex_prop->get_value()->as_string()
4573 : "";
4574
4575 ini::simple_property_sptr sym_name_not_regex_prop =
4576 is_simple_property(section.find_property("symbol_name_not_regexp"));
4577 string symbol_name_not_regex_str = sym_name_not_regex_prop
4578 ? sym_name_not_regex_prop->get_value()->as_string()
4579 : "";
4580
4581 ini::simple_property_sptr sym_version_prop =
4582 is_simple_property(section.find_property("symbol_version"));
4583 string symbol_version = sym_version_prop
4584 ? sym_version_prop->get_value()->as_string()
4585 : "";
4586
4587 ini::simple_property_sptr sym_version_regex_prop =
4588 is_simple_property(section.find_property("symbol_version_regexp"));
4589 string symbol_version_regex_str = sym_version_regex_prop
4590 ? sym_version_regex_prop->get_value()->as_string()
4591 : "";
4592
4593 ini::simple_property_sptr type_name_prop =
4594 is_simple_property(section.find_property("type_name"));
4595 string type_name_str = type_name_prop
4596 ? type_name_prop->get_value()->as_string()
4597 : "";
4598
4599 ini::simple_property_sptr type_name_regex_prop =
4600 is_simple_property(section.find_property("type_name_regexp"));
4601 string type_name_regex_str = type_name_regex_prop
4602 ? type_name_regex_prop->get_value()->as_string()
4603 : "";
4604
4605 result.reset(new variable_suppression(label_str,
4606 name_str,
4607 name_regex_str,
4608 symbol_name,
4609 symbol_name_regex_str,
4610 symbol_version,
4611 symbol_version_regex_str,
4612 type_name_str,
4613 type_name_regex_str));
4614
4615 if ((drop_artifact_str == "yes" || drop_artifact_str == "true")
4616 && (!name_str.empty()
4617 || !name_regex_str.empty()
4618 || !name_not_regex_str.empty()
4619 || !symbol_name.empty()
4620 || !symbol_name_regex_str.empty()
4621 || !symbol_name_not_regex_str.empty()))
4622 result->set_drops_artifact_from_ir(true);
4623
4624 if (!name_not_regex_str.empty())
4625 result->set_name_not_regex_str(name_not_regex_str);
4626
4627 if (!symbol_name_not_regex_str.empty())
4628 result->set_symbol_name_not_regex_str(symbol_name_not_regex_str);
4629
4630 if (!change_kind_str.empty())
4631 result->set_change_kind
4632 (variable_suppression::parse_change_kind(change_kind_str));
4633
4634 if (!file_name_regex_str.empty())
4635 result->set_file_name_regex_str(file_name_regex_str);
4636
4637 if (!file_name_not_regex_str.empty())
4638 result->set_file_name_not_regex_str(file_name_not_regex_str);
4639
4640 if (!soname_regex_str.empty())
4641 result->set_soname_regex_str(soname_regex_str);
4642
4643 if (!soname_not_regex_str.empty())
4644 result->set_soname_not_regex_str(soname_not_regex_str);
4645
4646 return result;
4647}
4648
4649/// Test if a given variable is suppressed by at least one suppression
4650/// specification among a vector of suppression specifications.
4651///
4652/// @param supprs the vector of suppression specifications to consider.
4653///
4654/// @param var_name the name of the variable to consider.
4655///
4656/// @param var_linkage_name the linkage name of the variable to consider.
4657///
4658/// @param require_drop_property if yes, then only suppression
4659/// specifications that require that the variable be dropped from the
4660/// internal representation are taking into account.
4661///
4662/// @return true if there is at least one suppression specification in
4663/// @p supprs which matches a variable named @p var_name, OR a
4664/// variable which linkage name is @p var_linkage_name.
4665bool
4667 const string& var_name,
4668 const string& var_linkage_name,
4669 bool require_drop_property)
4670{
4671 for (auto i : supprs)
4673 {
4674 if (require_drop_property && !i->get_drops_artifact_from_ir())
4675 continue;
4676 if (!var_name.empty()
4677 && suppression_matches_variable_name(*suppr, var_name))
4678 return true;
4679 if (!var_linkage_name.empty()
4681 var_linkage_name))
4682 return true;
4683 }
4684 return false;
4685}
4686// </variable_suppression stuff>
4687
4688// <file_suppression stuff>
4689
4690/// Constructor for the the @ref file_suppression type.
4691///
4692/// @param label the label of the suppression directive.
4693///
4694/// @param fname_regex_str the regular expression string that
4695/// designates the file name that instances of @ref file_suppression
4696/// should match.
4697///
4698/// @param fname_not_regex_str the regular expression string that
4699/// designates the file name that instances of @ref file_suppression
4700/// shoult *NOT* match. In other words, this file_suppression should
4701/// be activated if its file name does not match the regular
4702/// expression @p fname_not_regex_str.
4703file_suppression::file_suppression(const string& label,
4704 const string& fname_regex_str,
4705 const string& fname_not_regex_str)
4706 : suppression_base(label,
4707 fname_regex_str,
4708 fname_not_regex_str)
4709{}
4710
4711/// Test if instances of this @ref file_suppression suppresses a
4712/// certain instance of @ref diff.
4713///
4714/// This function always returns false because, obviously, a
4715/// file_suppression is meants to prevents Abigail tools from loading
4716/// some files. It is not meant to act on instance of @ref diff.
4717/// @return false.
4718bool
4720{return false;}
4721
4722/// Test if a instances of this @ref file_suppression suppresses a
4723/// given file.
4724///
4725/// @param file_path the file path to test against.
4726///
4727/// @return true iff this file_suppression matches the file path @p
4728/// file_path.
4729bool
4731{
4732 if (file_path.empty())
4733 return false;
4734
4735 string fname;
4736 tools_utils::base_name(file_path, fname);
4737
4738 bool has_regexp = false;
4739
4740 if (regex_t_sptr regexp = suppression_base::priv_->get_file_name_regex())
4741 {
4742 has_regexp = true;
4743 if (!regex::match(regexp, fname))
4744 return false;
4745 }
4746
4747 if (regex_t_sptr regexp = suppression_base::priv_->get_file_name_not_regex())
4748 {
4749 has_regexp = true;
4750 if (regex::match(regexp, fname))
4751 return false;
4752 }
4753
4754 if (!has_regexp)
4755 return false;
4756
4757 return true;
4758}
4759
4760/// Destructor of @ref file_suppression.
4764
4765/// Read a file suppression from an instance of ini::config::section
4766/// and build a @ref type_suppression as a result.
4767///
4768/// @param section the section (from an ini file) to read the file
4769/// suppression from.
4770///
4771/// @return file_suppression_sptr.
4773read_file_suppression(const ini::config::section& section)
4774{
4775 file_suppression_sptr result;
4776
4777 if (section.get_name() != "suppress_file")
4778 return result;
4779
4780 static const char *const sufficient_props[] = {
4781 "file_name_regexp",
4782 "file_name_not_regexp",
4783 "soname_regexp",
4784 "soname_not_regexp",
4785 };
4786 if (!check_sufficient_props(sufficient_props,
4787 sizeof(sufficient_props)/sizeof(char*),
4788 section))
4789 return result;
4790
4791 ini::simple_property_sptr label_prop =
4792 is_simple_property(section.find_property("label"));
4793 string label_str = (label_prop
4794 ? label_prop->get_value()->as_string()
4795 : "");
4796
4797 ini::simple_property_sptr file_name_regex_prop =
4798 is_simple_property(section.find_property("file_name_regexp"));
4799 string file_name_regex_str =
4800 file_name_regex_prop ? file_name_regex_prop->get_value()->as_string() : "";
4801
4802 ini::simple_property_sptr file_name_not_regex_prop =
4803 is_simple_property(section.find_property("file_name_not_regexp"));
4804 string file_name_not_regex_str =
4805 file_name_not_regex_prop
4806 ? file_name_not_regex_prop->get_value()->as_string()
4807 : "";
4808
4809 ini::simple_property_sptr soname_regex_prop =
4810 is_simple_property(section.find_property("soname_regexp"));
4811 string soname_regex_str =
4812 soname_regex_prop ? soname_regex_prop->get_value()->as_string() : "";
4813
4814 ini::simple_property_sptr soname_not_regex_prop =
4815 is_simple_property(section.find_property("soname_not_regexp"));
4816 string soname_not_regex_str =
4817 soname_not_regex_prop
4818 ? soname_not_regex_prop->get_value()->as_string()
4819 : "";
4820
4821 result.reset(new file_suppression(label_str,
4822 file_name_regex_str,
4823 file_name_not_regex_str));
4824
4825 if (!soname_regex_str.empty())
4826 {
4827 result->set_soname_regex_str(soname_regex_str);
4828 result->set_drops_artifact_from_ir(true);
4829 }
4830
4831 if (!soname_not_regex_str.empty())
4832 {
4833 result->set_soname_not_regex_str(soname_not_regex_str);
4834 result->set_drops_artifact_from_ir(true);
4835 }
4836
4837 return result;
4838}
4839
4840/// Test if a given suppression specification is a file suppression
4841/// specification.
4842///
4843/// @param s the instance of @ref suppression_base to test.
4844///
4845/// @return the instance of @ref file_suppression that @p s points to,
4846/// iff s is an instance of @ref file_suppression. Otherwise, returns
4847/// nil.
4850{return dynamic_pointer_cast<file_suppression>(s);}
4851
4852/// Test if a given file path is "suppressed" by at least one file
4853/// suppression specification among a vector of suppression
4854/// specifications.
4855///
4856/// @param file_path the file path to test.
4857///
4858/// @param sprs the vector of suppressions to use to test if one of
4859/// them at lease matches the file path @p file_path.
4860///
4861/// @return a pointer to the first instance of @ref file_suppression
4862/// that matches @p file_path, or nil if no file suppression matches.
4864file_is_suppressed(const string& file_path,
4865 const suppressions_type& sprs)
4866{
4867 for (suppressions_type::const_iterator i = sprs.begin(); i != sprs.end(); ++i)
4869 if (s->suppresses_file(file_path))
4870 return s;
4871
4872 return file_suppression_sptr();
4873}
4874
4875/// Test if a given SONAME is matched by a given suppression
4876/// specification.
4877///
4878/// @param soname the SONAME to consider.
4879///
4880/// @param suppr the suppression specification to consider.
4881///
4882/// @return true iff a given SONAME is matched by a given suppression
4883/// specification.
4884bool
4885suppression_matches_soname(const string& soname,
4886 const suppression_base& suppr)
4887{
4888 return suppr.priv_->matches_soname(soname);
4889}
4890
4891/// Test if a given SONAME or file name is matched by a given
4892/// suppression specification.
4893///
4894/// @param soname the SONAME to consider.
4895///
4896/// @param filename the file name to consider.
4897///
4898/// @param suppr the suppression specification to consider.
4899///
4900/// @return true iff either @p soname or @p filename is matched by the
4901/// suppression specification @p suppr.
4902bool
4904 const string& filename,
4905 const suppression_base& suppr)
4906{
4907 return (suppression_matches_soname(soname, suppr)
4908 || suppr.priv_->matches_binary_name(filename));
4909}
4910
4911/// @return the name of the artificial private type suppression
4912/// specification that is auto-generated by libabigail to suppress
4913/// change reports about types that are not defined in public headers.
4914const char*
4916{
4917 static const char *OPAQUE_TYPES_SUPPR_SPEC_NAME =
4918 "libabigail::OPAQUE_TYPE_LABEL";
4919
4920 return OPAQUE_TYPES_SUPPR_SPEC_NAME;
4921}
4922
4923/// Test if a type suppression specification represents a private type
4924/// suppression automatically generated by libabigail from the user
4925/// telling us where public headers are.
4926///
4927/// @param s the suppression specification we are looking at.
4928///
4929/// @return true iff @p s is a private type suppr spec.
4930bool
4933
4934/// Test if a type suppression specification represents a private type
4935/// suppression automatically generated by libabigail from the user
4936/// telling us where public headers are.
4937///
4938/// @param s the suppression specification we are looking at.
4939///
4940/// @return true iff @p s is a private type suppr spec.
4941bool
4943{
4945 return (type_suppr
4946 && type_suppr->get_label() == get_opaque_types_suppr_spec_label());
4947}
4948// </file_suppression stuff>
4949
4950/// Test if a given suppression specification can match an ABI
4951/// artifact coming from the corpus being analyzed by a given
4952/// front-end interface.
4953///
4954/// @param fe the front-end to consider.
4955///
4956/// @param s the suppression speficication to consider.
4957///
4958/// @return true if the suppression specification @p s CAN patch ABI
4959/// artifacts coming from the ABI corpus being analyzed by the
4960/// front-end @p fe.
4961bool
4963 const suppression_base& s)
4964{
4965 if (!s.priv_->matches_soname(fe.dt_soname()))
4967 // The suppression has some SONAME related properties, but
4968 // none of them match the SONAME of the current binary. So
4969 // the suppression cannot match the current binary.
4970 return false;
4971
4972 if (!s.priv_->matches_binary_name(fe.corpus_path()))
4974 // The suppression has some file_name related properties, but
4975 // none of them match the file name of the current binary. So
4976 // the suppression cannot match the current binary.
4977 return false;
4978
4979 return true;
4980}
4981
4982/// Test if a given function is suppressed by a suppression
4983/// specification.
4984///
4985/// @param fe the front-end to consider.
4986///
4987/// @param s the suppression specification to consider.
4988///
4989/// @param fn_name the name of the function to consider.
4990///
4991/// @return true iff the suppression specification @p s matches the
4992/// function which name is @p fn_name.
4993bool
4994suppression_matches_function_name(const fe_iface& fe,
4996 const string& fn_name)
4997{
4998 if (!suppression_can_match(fe, s))
4999 return false;
5000
5001 if (regex::regex_t_sptr regexp = s.priv_->get_name_regex())
5002 {
5003 if (!regex::match(regexp, fn_name))
5004 return false;
5005 }
5006 else if (regex::regex_t_sptr regexp = s.priv_->get_name_not_regex())
5007 {
5008 if (regex::match(regexp, fn_name))
5009 return false;
5010 }
5011 else if (s.priv_->name_.empty())
5012 return false;
5013 else // if (!s.priv_->name_.empty())
5014 {
5015 if (s.priv_->name_ != fn_name)
5016 return false;
5017 }
5018
5019 return true;
5020}
5021
5022/// Test if a given function is suppressed by a suppression
5023/// specification.
5024///
5025/// @param fe the front-end to consider.
5026///
5027/// @param s the suppression specification to consider.
5028///
5029/// @param fn_linkage_name the linkage name of the function to
5030/// consider.
5031///
5032/// @return true iff the suppression specification @p s matches the
5033/// function which linkage name is @p fn_linkage_name.
5034bool
5035suppression_matches_function_sym_name(const fe_iface& fe,
5037 const string& fn_linkage_name)
5038{
5039 if (!suppression_can_match(fe, s))
5040 return false;
5041
5042 if (regex::regex_t_sptr regexp = s.priv_->get_symbol_name_regex())
5043 {
5044 if (!regex::match(regexp, fn_linkage_name))
5045 return false;
5046 }
5047 else if (regex::regex_t_sptr regexp = s.priv_->get_symbol_name_not_regex())
5048 {
5049 if (regex::match(regexp, fn_linkage_name))
5050 return false;
5051 }
5052 else if (s.priv_->symbol_name_.empty())
5053 return false;
5054 else // if (!s.priv_->symbol_name_.empty())
5055 {
5056 if (s.priv_->symbol_name_ != fn_linkage_name)
5057 return false;
5058 }
5059
5060 return true;
5061}
5062
5063/// Test if a suppression specification matches a variable of a given
5064/// name, in the context of a given front-end.
5065///
5066/// @param fe the front-end to consider.
5067///
5068/// @param s the variable suppression specification to consider.
5069///
5070/// @param var_name the name of the variable to consider.
5071///
5072/// @return true iff the suppression specification @p s matches the
5073/// variable which name is @p var_name.
5074bool
5077 const string& var_name)
5078{
5079 if (!suppression_can_match(fe, s))
5080 return false;
5081
5082 return suppression_matches_variable_name(s, var_name);
5083}
5084
5085/// Test if a suppression specification matches a variable which ELF
5086/// symbol has a given name, in the context of a given front-end.
5087///
5088/// @param fe the front-end to consider.
5089///
5090/// @param s the variable suppression specification to consider.
5091///
5092/// @param var_linkage_name the name of the ELF symbol of the variable
5093/// to consider.
5094///
5095/// @return true iff the suppression specification @p s matches the
5096/// variable which ELF symbol name is @p var_linkage_name.
5097bool
5100 const string& var_linkage_name)
5101{
5102 if (!suppression_can_match(fe, s))
5103 return false;
5104
5105 return suppression_matches_variable_sym_name(s, var_linkage_name);
5106}
5107
5108/// Test if a suppression specification matches a type designated by
5109/// its name and source location, in the context of a given front-end.
5110///
5111/// @param fe the front-end to consider.
5112///
5113/// @param s the suppression specification to consider.
5114///
5115/// @param type_name the name of the type to consider.
5116///
5117/// @param type_location the source location of the type designated by
5118/// @p type_name.
5119///
5120/// @return true iff the suppression @p s matches the type designated
5121/// by @p type_name at source location @type_location.
5122bool
5124 const suppr::type_suppression& s,
5125 const string& type_name,
5126 const location& type_location)
5127{
5128 if (!suppression_can_match(fe, s))
5129 return false;
5130
5132 type_location);
5133}
5134
5135/// Test if an ELF symbol is suppressed by at least one of the
5136/// suppression specifications associated with a given front-end.
5137///
5138/// The function looks for each suppression specification provided to
5139/// a given libabigail front-end and analyzes them to see if they
5140/// match a given ELF symbol.
5141///
5142/// @param fe the front-end to consider.
5143///
5144/// @param symbol the ELF symbol to consider.
5145///
5146/// @return true iff the symbol @p symbol is matched by at least a
5147/// suppression specification associated with the front-end @p fe.
5148bool
5150 const elf_symbol_sptr& symbol)
5151{
5152 if (elf_symbol_is_function(symbol->get_type()))
5153 return is_function_suppressed(fe, /*fn_name=*/"",
5154 /*symbol_name=*/symbol->get_name());
5155 else if (elf_symbol_is_variable(symbol->get_type()))
5156 return is_variable_suppressed(fe, /*var_name=*/"",
5157 /*symbol_name=*/symbol->get_name());
5158 return false;
5159}
5160
5161/// Test if an ELF symbol is suppressed by at least one of the
5162/// suppression specifications associated with a given front-end.
5163///
5164/// The function looks for each suppression specification provided to
5165/// a given libabigail front-end and analyzes them to see if they
5166/// match a given ELF symbol, designated by its name and kind.
5167///
5168/// @param fe the front-end to consider.
5169///
5170/// @param sym_name the name of the symbol to consider.
5171///
5172/// @return true iff the symbol denoted by @p sym_name, of kind @p
5173/// sym_type, is matched by at least a suppression specification
5174/// associated with the front-end @p fe.
5175bool
5177 const string& sym_name,
5178 elf_symbol::type sym_type)
5179{
5180 if (elf_symbol_is_function(sym_type))
5181 return is_function_suppressed(fe, /*fn_name=*/"",
5182 /*symbol_name=*/sym_name);
5183 else if (elf_symbol_is_variable(sym_type))
5184 return is_variable_suppressed(fe, /*var_name=*/"",
5185 /*symbol_name=*/sym_name);
5186 return false;
5187}
5188
5189/// Test if a function is matched by at least one suppression
5190/// specification associated with a given front-end.
5191///
5192/// The function is designated by its name and its linkage_name.
5193///
5194/// @param fe the front-end to consider.
5195///
5196/// @param fn_name the name of the function to consider.
5197///
5198/// @param fn_linkage_name the linkage name of the function to
5199/// consider.
5200///
5201/// @param require_drop_property if true, this function requires the
5202/// suppression specification to contain the "drop" property to match
5203/// the function.
5204///
5205/// @return true iff the function is matched by at least one
5206/// suppression specification coming from the front-end.
5207bool
5209 const string& fn_name,
5210 const string& fn_linkage_name,
5211 bool require_drop_property)
5212{
5213 for (auto i : fe.suppressions())
5215 {
5216 if (require_drop_property && !i->get_drops_artifact_from_ir())
5217 continue;
5218 if (!fn_name.empty()
5219 && suppression_matches_function_name(fe, *suppr, fn_name))
5220 return true;
5221 if (!fn_linkage_name.empty()
5222 && suppression_matches_function_sym_name(fe, *suppr,
5223 fn_linkage_name))
5224 return true;
5225 }
5226 return false;
5227}
5228
5229/// Test if a variable is matched by at least one suppression
5230/// specification associated with a given front-end.
5231///
5232/// The variable is designated by its name and its linkage_name.
5233///
5234/// @param fe the front-end to consider.
5235///
5236/// @param var_name the name of the variable to consider.
5237///
5238/// @param var_linkage_name the linkage name of the variable to
5239/// consider.
5240///
5241/// @param require_drop_property if true, this variable requires the
5242/// suppression specification to contain the "drop" property to match
5243/// the function.
5244///
5245/// @return true iff the variable is matched by at least one
5246/// suppression specification coming from the front-end.
5247bool
5249 const string& var_name,
5250 const string& var_linkage_name,
5251 bool require_drop_property)
5252{
5253 for (auto i : fe.suppressions())
5255 {
5256 if (require_drop_property && !i->get_drops_artifact_from_ir())
5257 continue;
5258 if (!var_name.empty()
5259 && suppression_matches_variable_name(fe, *suppr, var_name))
5260 return true;
5261 if (!var_linkage_name.empty()
5263 var_linkage_name))
5264 return true;
5265 }
5266 return false;
5267}
5268
5269/// Test if a type is matched by at least one suppression
5270/// specification associated with a given front-end.
5271///
5272/// The type is designated by its name and its source location.
5273///
5274/// @param fe the front-end to consider.
5275///
5276/// @param type_name the name of the type to consider.
5277///
5278/// @param type_location the source location of the type.
5279///
5280/// @param type_is_opaque output parameter. This is set to true if
5281/// the type was matched by one suppression specification, and if the
5282/// suppression was for opaque types.
5283///
5284/// @param require_drop_property if true, this type requires the
5285/// suppression specification to contain the "drop" property to match
5286/// the type.
5287///
5288/// @return true iff the type is matched by at least one suppression
5289/// specification coming from the front-end.
5290bool
5292 const string& type_name,
5293 const location& type_location,
5294 bool& type_is_opaque,
5295 bool require_drop_property)
5296{
5297 for (auto i : fe.suppressions())
5299 {
5300 if (require_drop_property && !i->get_drops_artifact_from_ir())
5301 continue;
5303 type_name,
5304 type_location))
5305 {
5306 if (is_opaque_type_suppr_spec(*suppr))
5307 type_is_opaque = true;
5308
5309 return true;
5310 }
5311 }
5312
5313 type_is_opaque = false;
5314 return false;
5315}
5316
5317/// Test if a data memer offset is in a given insertion range.
5318///
5319/// @param dm the data member to consider.
5320///
5321/// @param range the insertion range to consider.
5322///
5323/// @param the class (or union) type to consider as the context in
5324/// which to evaluate the insertion range denoted by @p range.
5325///
5326/// @return true iff the offset of the data member @p dm is in the
5327/// insertion range @p range in the context of the type denoted by @p
5328/// context.
5329bool
5332 const class_or_union* context)
5333{
5334 ABG_ASSERT(dm && range && context);
5335
5336 uint64_t range_begin = 0, range_end = 0;
5338 context,
5339 range_begin))
5340 return false;
5341
5343 context,
5344 range_end))
5345 return false;
5346
5347 if (range_begin > range_end)
5348 // wrong range, ignore it.
5349 return false;
5350
5351 uint64_t dm_offset = get_data_member_offset(dm);
5354 {
5355 // This idiom represents the predicate
5356 // "has_data_member_inserted_at = end"
5357 if (dm_offset > get_data_member_offset(get_last_data_member(context)))
5358 return true;
5359 return false;
5360 }
5361
5362 if (dm_offset < range_begin || dm_offset > range_end)
5363 // The offset of the data member is outside the range.
5364 return false;
5365
5366 return true;
5367}
5368
5369}// end namespace suppr
5370} // end namespace abigail
This header declares filters for the diff trees resulting from comparing ABI Corpora.
This file contains the declarations for the fe_iface a.k.a "Front End Interface".
#define ABG_ASSERT(cond)
This is a wrapper around the 'assert' glibc call. It allows for its argument to have side effects,...
Definition abg-fwd.h:1743
This file contains the declarations for the ini file reader used in the libabigail library.
This contains the private implementation of the suppression engine of libabigail.
This type abstracts changes for a class_decl.
class_decl_sptr first_class_decl() const
class_decl_sptr second_class_decl() const
Getter of the second class involved in the diff.
This is the base class of class_diff and union_diff.
const unsigned_var_diff_sptr_map & changed_data_members() const
Getter of the map of data members that got replaced by another data member. The key of the map is the...
class_or_union_sptr first_class_or_union() const
const string_decl_base_sptr_map & inserted_data_members() const
Getter for the data members that got inserted.
The context of the diff. This type holds various bits of information that is going to be used through...
const corpus_diff_sptr & get_corpus_diff() const
Get the corpus diff for the current context.
The abstraction of a change between two ABI artifacts, a.k.a an artifact change.
type_or_decl_base_sptr second_subject() const
Getter of the second subject of the diff.
type_or_decl_base_sptr first_subject() const
Getter of the first subject of the diff.
const diff_context_sptr context() const
Getter of the context of the current diff.
Abstraction of a diff between two enums.
const string_changed_enumerator_map & changed_enumerators() const
const enum_type_decl_sptr first_enum() const
const string_enumerator_map & deleted_enumerators() const
const enum_type_decl_sptr second_enum() const
Abstraction of a diff between two function_decl.
const function_decl_sptr second_function_decl() const
const function_decl_sptr first_function_decl() const
The abstraction of a diff between two pointers.
The abstraction of a diff between two references.
The base class of diff between types.
Abstracts a diff between two instances of var_decl.
This type abstracts the configuration information of the library.
Definition abg-config.h:18
The base class of all libabigail front-ends: The Front End Interface.
suppr::suppressions_type & suppressions()
Getter of the vector of suppression specifications associated with the current front-end.
const std::string & corpus_path() const
Getter of the path to the file which an ABI corpus is to be created for.
const string & dt_soname() const
Getter for the SONAME of the analyzed binary.
The abstraction of one section of the .ini config.
Definition abg-ini.h:359
const string & get_name() const
Get the name of the section.
Definition abg-ini.cc:812
property_sptr find_property(const string &prop_name) const
Find a property that has a given name.
Definition abg-ini.cc:845
const vector< string > & get_content() const
Getter of the content of the list_property_value.
Definition abg-ini.cc:396
virtual const string & as_string() const
Convert the string property value into a string.
Definition abg-ini.cc:325
The base type of class_decl and union_decl.
Definition abg-ir.h:3977
const data_members & get_data_members() const
Get the data members of this class_or_union.
Definition abg-ir.cc:24233
virtual void get_qualified_name(interned_string &qualified_name, bool internal=false) const
Compute the qualified name of the decl.
Definition abg-ir.cc:4823
const string & str() const
Getter for the version name.
Definition abg-ir.cc:3205
Abstraction of an elf symbol.
Definition abg-ir.h:961
bool is_variable() const
Test if the current instance of elf_symbol is a variable symbol or not.
Definition abg-ir.cc:2299
const string & get_name() const
Getter for the name of the elf_symbol.
Definition abg-ir.cc:2159
bool is_function() const
Test if the current instance of elf_symbol is a function symbol or not.
Definition abg-ir.cc:2290
type
The type of a symbol.
Definition abg-ir.h:965
version & get_version() const
Getter for the version of the current instanc of elf_symbol.
Definition abg-ir.cc:2218
Abstraction for a function declaration.
Definition abg-ir.h:3165
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition abg-ir.h:3187
const function_type_sptr get_type() const
Return the type of the current instance of function_decl.
Definition abg-ir.cc:22974
const elf_symbol_sptr & get_symbol() const
Gets the the underlying ELF symbol for the current variable, that was set using function_decl::set_sy...
Definition abg-ir.cc:23027
The source location of a token.
Definition abg-ir.h:307
void expand(std::string &path, unsigned &line, unsigned &column) const
Expand the current location into a tripplet file path, line and column number.
Definition abg-ir.cc:452
A declaration that introduces a scope.
Definition abg-ir.h:1853
Abstracts a variable declaration.
Definition abg-ir.h:3068
virtual const interned_string & get_qualified_name(bool internal=false) const
Get the qualified name of a given variable or data member.
Definition abg-ir.cc:21740
const type_base_sptr get_type() const
Getter of the type of the variable.
Definition abg-ir.cc:21419
const elf_symbol_sptr & get_symbol() const
Gets the the underlying ELF symbol for the current variable, that was set using var_decl::set_symbol(...
Definition abg-ir.cc:21482
Abstraction of a suppression specification to avoid loading a file.
virtual ~file_suppression()
Destructor of file_suppression.
bool suppresses_file(const string &file_path)
Test if a instances of this file_suppression suppresses a given file.
virtual bool suppresses_diff(const diff *diff) const
Test if instances of this file_suppression suppresses a certain instance of diff.
const string & get_parameter_type_name() const
Getter for the type name of the parameter designated by this specification.
const string & get_parameter_type_name_regex_str() const
Getter for the regular expression that defines a set of type names for the parameter designated by th...
void set_parameter_type_name_regex_str(const string &)
Setter for the regular expression that defines a set of type names for the parameter designated by th...
void set_parameter_type_name(const string &)
Setter for the type name of the parameter designated by this specification.
void set_index(size_t)
Setter for the index of the parameter designated by this specification.
size_t get_index() const
Getter for the index of the parameter designated by this specification.
Abstraction of a function suppression specification.
void set_name_regex_str(const string &)
Setter for a regular expression for a family of names of functions the user wants the current specifi...
change_kind get_change_kind() const
Getter of the "change-kind" property.
const string & get_symbol_version() const
Getter for the name of the version of the symbol of the function the user wants this specification to...
void set_change_kind(change_kind k)
Setter of the "change-kind" property.
change_kind
The kind of change the current function suppression should apply to.
@ ALL_CHANGE_KIND
This represents all the changes possibly described by this enum. It's a logical 'OR' of all the chang...
@ ADDED_FUNCTION_CHANGE_KIND
The function was added to the second subject of the diff.
@ FUNCTION_SUBTYPE_CHANGE_KIND
A change in a sub-type of the function.
@ DELETED_FUNCTION_CHANGE_KIND
The function was deleted from the second subject of the diff.
const string & get_symbol_version_regex_str() const
Getter for a regular expression for a family of versions of symbols of functions the user wants the c...
bool suppresses_function(const function_decl *fn, change_kind k, const diff_context_sptr ctxt) const
Evaluate the current function suppression specification on a given function_decl and say if a report ...
const string & get_return_type_name() const
Getter for the name of the return type of the function the user wants this specification to designate...
static change_kind parse_change_kind(const string &)
Parses a string containing the content of the "change-kind" property and returns the an instance of f...
bool suppresses_function_symbol(const elf_symbol *sym, change_kind k, const diff_context_sptr ctxt)
Evaluate the current function suppression specification on a given elf_symbol and say if a report abo...
void set_return_type_name(const string &)
Setter for the name of the return type of the function the user wants this specification to designate...
const string & get_name() const
Getter for the name of the function the user wants the current specification to designate....
const string & get_symbol_name() const
Getter for the name of symbol of the function the user wants this specification to designate.
vector< parameter_spec_sptr > parameter_specs_type
Convenience typedef for vector of parameter_spec_sptr.
void set_symbol_name_regex_str(const string &)
Setter for a regular expression for a family of names of symbols of functions the user wants this spe...
const string & get_symbol_name_regex_str() const
Getter for a regular expression for a family of names of symbols of functions the user wants this spe...
void set_symbol_name_not_regex_str(const string &)
Setter for a regular expression for a family of names of symbols of functions the user wants this spe...
void set_name_not_regex_str(const string &)
Setter for a regular expression for a family of names of functions the user wants the current specifi...
void set_symbol_version(const string &)
Setter for the name of the version of the symbol of the function the user wants this specification to...
void set_parameter_specs(parameter_specs_type &)
Setter for a vector of parameter specifications to specify properties of the parameters of the functi...
void set_name(const string &)
Setter for the name of the function the user wants the current specification to designate....
const parameter_specs_type & get_parameter_specs() const
Getter for a vector of parameter specifications to specify properties of the parameters of the functi...
virtual bool suppresses_diff(const diff *diff) const
Evaluate this suppression specification on a given diff node and say if the diff node should be suppr...
void set_return_type_regex_str(const string &r)
Setter for a regular expression for a family of return type names for functions the user wants the cu...
const string & get_name_not_regex_str() const
Getter for a regular expression of a family of names of functions the user wants the current specific...
void set_symbol_name(const string &n)
Setter for the name of symbol of the function the user wants this specification to designate.
const string & get_symbol_name_not_regex_str() const
Getter for a regular expression for a family of names of symbols of functions the user wants this spe...
void append_parameter_specs(const parameter_spec_sptr)
Append a specification of a parameter of the function specification.
void set_allow_other_aliases(bool f)
Setter for the "allow_other_aliases" property of the function suppression specification.
void set_symbol_version_regex_str(const string &)
Setter for a regular expression for a family of versions of symbols of functions the user wants the c...
function_suppression()
Default constructor for the function_suppression type.
const string & get_name_regex_str() const
Getter for a regular expression for a family of names of functions the user wants the current specifi...
bool get_allow_other_aliases() const
Getter for the "allow_other_aliases" property of the function suppression specification.
const string & get_return_type_regex_str() const
Getter for a regular expression for a family of return type names for functions the user wants the cu...
shared_ptr< parameter_spec > parameter_spec_sptr
Convenience typedef for shared_ptr of parameter_spec.
The base class of suppression specifications that are defined by the negation of matching clauses.
virtual ~negated_suppression_base()
Destructor of the negated_suppression_base.
negated_suppression_base()
Constructor of the negated_suppression_base.
negated_type_suppression(const string &label, const string &type_name_regexp, const string &type_name)
Constructor for negated_type_suppression.
virtual bool suppresses_diff(const diff *diff) const
Evaluate this suppression specification on a given diff node and say if the diff node should be suppr...
virtual ~negated_type_suppression()
Destructor of the negated_type_suppression type.
The private data of suppression_base.
Base type of a direct suppression specifications types.
const string & get_file_name_regex_str() const
Getter for the "file_name_regex" property of the current instance of suppression_base.
bool get_drops_artifact_from_ir() const
Tests if the current suppression specification is to avoid adding the matched ABI artifact to the int...
bool get_is_artificial() const
Test is the suppression specification is artificial.
void set_file_name_regex_str(const string &regexp)
Setter for the "file_name_regex" property of the current instance of suppression_base.
void set_soname_not_regex_str(const string &regexp)
Setter of the "soname_not_regex_str property of the current instance of suppression_base.
const string & get_soname_not_regex_str() const
Getter of the "soname_not_regex_str property of the current instance of suppression_base.
const string get_label() const
Getter for the label associated to this suppression specification.
void set_file_name_not_regex_str(const string &regexp)
Setter for the "file_name_not_regex" property of the current instance of suppression_base.
void set_is_artificial(bool)
Set a flag saying if the suppression specification is artificial or not.
const string & get_file_name_not_regex_str() const
Getter for the "file_name_not_regex" property of the current instance of suppression_base.
void set_label(const string &)
Setter for the label associated to this suppression specification.
const string & get_soname_regex_str() const
Getter of the "soname_regex_str property of the current instance of suppression_base.
bool has_soname_related_property() const
Test if the current suppression has a property related to SONAMEs.
void set_soname_regex_str(const string &regexp)
Setter of the "soname_regex_str property of the current instance of suppression_base.
bool has_file_name_related_property() const
Test if the current suppression has a property related to file name.
void set_drops_artifact_from_ir(bool)
Set the flag that says whether the current suppression specification is to avoid adding the matched A...
The abstraction of the boundary of an insertion_range, in the context of a type_suppression.
virtual ~boundary()
Destructor of type_suppression::insertion_range::boundary.
boundary()
Default constructor of type_suppression::insertion_range::boundary.
An insertion_range boundary that is expressed as function call expression. The (integer) value of tha...
~fn_call_expr_boundary()
Destructor of type_suppression::insertion_range::fn_call_expr_boundary.
ini::function_call_expr_sptr as_function_call_expr() const
Returns the function call expression value of the current boundary.
An insertion_range boundary that is expressed as an integer value. That integer value is usually a bi...
~integer_boundary()
Destructor of type_suppression::insertion_range::integer_boundary.
uint64_t as_integer() const
Return the integer value of the current instance of type_suppression::insertion_range::integer_bounda...
An insertion_range boundary that is expressed as a named constant that is to be evaluated later in th...
const string & get_name() const
Getter for the name of the named boundary.
static insertion_range::named_boundary_sptr create_named_boundary(const string &)
Create a named boundary.
shared_ptr< named_boundary > named_boundary_sptr
Convenience typedef for a shared_ptr to a named_boundary.
static insertion_range::integer_boundary_sptr create_integer_boundary(int value)
Create an integer boundary.
static insertion_range::fn_call_expr_boundary_sptr create_fn_call_expr_boundary(ini::function_call_expr_sptr)
Create a function call expression boundary.
shared_ptr< fn_call_expr_boundary > fn_call_expr_boundary_sptr
Convenience typedef for a shared_ptr to a fn_call_expr_boundary.
boundary_sptr end() const
Getter for the end of the range.
static bool boundary_value_is_end(uint64_t value)
Test if a given value supposed to be inside an insertion range represents the end of the range.
shared_ptr< integer_boundary > integer_boundary_sptr
Convenience typedef for a shared_ptr to a integer_boundary.
static bool eval_boundary(const boundary_sptr boundary, const class_or_union *context, uint64_t &value)
Evaluate an insertion range boundary to get a resulting integer value.
shared_ptr< boundary > boundary_sptr
Convenience typedef for a shared_ptr to boundary.
boundary_sptr begin() const
Getter for the beginning of the range.
insertion_range()
Default Constructor of type_suppression::insertion_range.
The private data for type_suppression.
Abstraction of a type suppression specification.
void set_type_name_not_regex_str(const string &name_regex_str)
Setter for the "type_name_not_regex_str" property of the type suppression specification.
const vector< string > & get_changed_enumerator_names() const
Getter of the vector of the changed enumerators that are supposed to be suppressed....
void set_type_name_regex_str(const string &name_regex_str)
Setter for the "type_name_regex" property of the type suppression specification.
void set_type_name(const string &name)
Setter for the name of the type about which diff reports should be suppressed.
void set_consider_type_kind(bool f)
Setter of the property that says whether to consider the kind of type this suppression is about.
reach_kind get_reach_kind() const
Getter of the way the diff node matching the current suppression specification is to be reached.
const vector< regex::regex_t_sptr > & get_changed_enumerators_regexp() const
Getter of the vector of the regular expression strings for changed enumerators that are supposed to b...
void set_changed_enumerators_regexp(const vector< regex::regex_t_sptr > &)
Setter of the vector of the regular expression strings for changed enumerators that are supposed to b...
const string & get_source_location_to_keep_regex_str() const
Getter of the regular expression string that designates the source location paths of types that shoul...
vector< insertion_range_sptr > insertion_ranges
A convenience typedef for a vector of insertion_range_sptr.
void set_changed_enumerator_names(const vector< string > &)
Setter of the vector of changed enumerators that are supposed to be suppressed. Note that this will b...
bool has_strict_fam_conversion() const
Getter of the "has_string_fam_conversion" property.
void set_source_location_to_keep_regex_str(const string &)
Setter of the regular expression string that designates the source location paths of types that shoul...
void set_source_locations_to_keep(const unordered_set< string > &)
Setter for the array of source location paths of types that should *NOT* be suppressed.
bool get_consider_type_kind() const
Getter of the property that says whether to consider the kind of type this suppression is about.
type_kind
The kind of the type the current type suppression is supposed to be about.
const string & get_type_name_regex_str() const
Getter for the "type_name_regex" property of the type suppression specification.
void set_consider_reach_kind(bool f)
Set a flag saying if the current type suppression specification suggests to consider how the matching...
type_kind get_type_kind() const
Getter of the kind of type this suppression is about.
void set_type_kind(type_kind k)
Setter of the kind of type this suppression is about.
void set_has_strict_fam_conversion(bool)
Setter of the "has_string_fam_conversion" property.
const insertion_ranges & get_data_member_insertion_ranges() const
Getter for the vector of data member insertion range that specifiers where a data member is inserted ...
const string_set_type & get_potential_data_member_names() const
Getter of the "potential_data_member_names" property.
reach_kind
The different ways through which the type diff has been reached.
@ REFERENCE_REACH_KIND
The type diff has been reached (from a function or variable change) through a reference; you know,...
@ POINTER_REACH_KIND
The type diff has been reached (from a function or variable change) through a pointer.
@ REFERENCE_OR_POINTER_REACH_KIND
The type diff has been reached (from a function or variable change) through either a reference or a p...
@ DIRECT_REACH_KIND
The type diff has been reached (from a function or variable change) directly.
bool get_consider_reach_kind() const
Test if the current type suppression specification suggests to consider how the matching diff node is...
const unordered_set< string > & get_source_locations_to_keep() const
Getter for the array of source location paths of types that should *NOT* be suppressed.
const string & get_type_name_not_regex_str() const
Getter for the "type_name_not_regex_str" property of the type suppression specification.
virtual bool suppresses_diff(const diff *diff) const
Evaluate this suppression specification on a given diff node and say if the diff node should be suppr...
bool suppresses_type(const type_base_sptr &type, const diff_context_sptr &ctxt) const
Test if the current instance of type_suppression suppresses a change reports about a given type.
void set_has_size_change(bool flag)
Setter of the "has_size_change" property.
void set_reach_kind(reach_kind k)
Setter of the way the diff node matching the current suppression specification is to be reached.
void set_potential_data_member_names(const string_set_type &) const
Setter of the "potential_data_member_names" property.
bool get_has_size_change() const
Getter of the "has_size_change" property.
const string & get_potential_data_member_names_regex_str() const
Getter of the "potential_data_member_names_regex" string.
const string & get_type_name() const
Getter for the name of the type about which diff reports should be suppressed.
void set_data_member_insertion_ranges(const insertion_ranges &r)
Setter for the vector of data member insertion ranges that specifies where a data member is inserted ...
void set_potential_data_member_names_regex_str(const string &) const
Setter of the "potential_data_member_names_regex" string.
shared_ptr< insertion_range > insertion_range_sptr
A convenience typedef for a shared pointer to insertion_range.
The abstraction of a variable suppression specification.
void set_symbol_name(const string &)
Setter for the name of the symbol of the variable the user wants the current specification to designa...
void set_name_regex_str(const string &)
Setter for the regular expression for a family of names of variables the user wants the current speci...
virtual ~variable_suppression()
Virtual destructor for the @erf variable_suppression type. variable_suppression type.
const string & get_symbol_version() const
Getter for the version of the symbol of the variable the user wants the current specification to desi...
variable_suppression(const string &label="", const string &name="", const string &name_regex_str="", const string &symbol_name="", const string &symbol_name_regex_str="", const string &symbol_version="", const string &symbol_version_regex_str="", const string &type_name="", const string &type_name_regex_str="")
Constructor for the variable_suppression type.
void set_change_kind(change_kind k)
Setter of the "change_kind" property.
static change_kind parse_change_kind(const string &)
Parses a string containing the content of the "change-kind" property and returns the an instance of v...
change_kind
The kind of change the current variable suppression should apply to.
@ ADDED_VARIABLE_CHANGE_KIND
The variable was added to the second second subject of the diff.
@ ALL_CHANGE_KIND
This represents all the changes possibly described by this enum. It's a logical 'OR' of all the chang...
@ DELETED_VARIABLE_CHANGE_KIND
The variable was deleted from the second subject of the diff.
@ VARIABLE_SUBTYPE_CHANGE_KIND
A change in a sub-type of the variable.
const string & get_symbol_version_regex_str() const
Getter of the regular expression for a family of versions of symbol for the variables the user wants ...
const string & get_name() const
Getter for the name of the variable the user wants the current specification to designate....
const string & get_symbol_name() const
Getter for the name of the symbol of the variable the user wants the current specification to designa...
void set_symbol_name_regex_str(const string &)
Setter of the regular expression for a family of symbol names of the variables this specification is ...
const string & get_symbol_name_regex_str() const
Getter of the regular expression for a family of symbol names of the variables this specification is ...
const string & get_type_name_regex_str() const
Getter for the regular expression for a family of type names of variables the user wants the current ...
void set_symbol_name_not_regex_str(const string &)
Setter for a regular expression for a family of names of symbols of variables the user wants this spe...
void set_type_name(const string &)
Setter for the name of the type of the variable the user wants the current specification to designate...
change_kind get_change_kind() const
Getter of the "change_king" property.
void set_name_not_regex_str(const string &)
Setter for the "name_not_regexp" property of the specification.
void set_symbol_version(const string &)
Setter for the version of the symbol of the variable the user wants the current specification to desi...
bool suppresses_variable(const var_decl *var, change_kind k, const diff_context_sptr cxt) const
Evaluate the current variable suppression specification on a given var_decl and say if a report about...
void set_name(const string &)
Setter for the name of the variable the user wants the current specification to designate....
const string & get_name_not_regex_str() const
Getter for the "name_not_regexp" property of the specification.
const string & get_symbol_name_not_regex_str() const
Getter for a regular expression for a family of names of symbols of variables the user wants this spe...
void set_type_name_regex_str(const string &)
Setter for the regular expression for a family of type names of variables the user wants the current ...
void set_symbol_version_regex_str(const string &)
Setter of the regular expression for a family of versions of symbol for the variables the user wants ...
const string & get_type_name() const
Getter for the name of the type of the variable the user wants the current specification to designate...
bool suppresses_diff(const diff *d) const
Evaluate this suppression specification on a given diff node and say if the diff node should be suppr...
const string & get_name_regex_str() const
Getter for the regular expression for a family of names of variables the user wants the current speci...
bool suppresses_variable_symbol(const elf_symbol *sym, change_kind k, const diff_context_sptr cxt) const
Evaluate the current variable suppression specification on a given elf_symbol and say if a report abo...
bool has_strict_fam_conversion(const class_decl_sptr &first, const class_decl_sptr &second)
Test if a class with a fake flexible data member got changed into a class with a real fexible data me...
const diff * peel_qualified_diff(const diff *dif)
If a diff node is about changes between two qualified types, get the diff node about changes between ...
const pointer_diff * is_pointer_diff(const diff *diff)
Test if a diff node is about differences between two pointers.
shared_ptr< diff_context > diff_context_sptr
Convenience typedef for a shared pointer of diff_context.
Definition abg-fwd.h:70
const function_decl_diff * is_function_decl_diff(const diff *diff)
Test if a diff node is about differences between functions.
visiting_kind operator&(visiting_kind l, visiting_kind r)
The overloaded and operator for visiting_kind.
visiting_kind operator|(visiting_kind l, visiting_kind r)
The overloaded or operator for visiting_kind.
const class_or_union_diff * is_class_or_union_diff(const diff *d)
Test if a diff node is a class_or_union_diff node.
const diff * get_typedef_diff_underlying_type_diff(const diff *diff)
Return the leaf underlying diff node of a typedef_diff node.
const var_diff * is_var_diff(const diff *diff)
Test if a diff node is about differences between variables.
const type_diff_base * is_type_diff(const diff *diff)
Test if a diff node is about differences between types.
const reference_diff * is_reference_diff(const diff *diff)
Test if a diff node is about differences between two references.
shared_ptr< list_property_value > list_property_value_sptr
A convenience typedef for a shared_ptr to list_property_value.
Definition abg-ini.h:130
bool read_function_call_expr(std::istream &input, function_call_expr_sptr &expr)
Read a function call expression and build its representation.
Definition abg-ini.cc:2017
list_property * is_list_property(const property *p)
Test if an instance of a property is actually an instance of list_property.
Definition abg-ini.cc:686
shared_ptr< property > property_sptr
Convenience typefef for shared_ptr to property.
Definition abg-ini.h:36
shared_ptr< list_property > list_property_sptr
A convenience typedef for a shared_ptr to a list_property.
Definition abg-ini.h:244
shared_ptr< config > config_sptr
A convenience typedef for a shared pointer to config.
Definition abg-ini.h:316
list_property_value * is_list_property_value(const property_value *v)
Test if an instance of @property_value is a list_property_value.
Definition abg-ini.cc:437
bool read_config(istream &input, config &conf)
Parse an ini config file from an input stream.
Definition abg-ini.cc:1747
shared_ptr< tuple_property > tuple_property_sptr
Convenience typedef for a shared_ptr of tuple_property.
Definition abg-ini.h:282
shared_ptr< simple_property > simple_property_sptr
Convenience typedef for a shared_ptr to an simple_property.
Definition abg-ini.h:206
shared_ptr< function_call_expr > function_call_expr_sptr
Convenience typedef for a shared pointer to function_call_expr.
Definition abg-ini.h:430
shared_ptr< string_property_value > string_property_value_sptr
A convenience typedef for a shared_ptr to string_property_value.
Definition abg-ini.h:97
string_property_value * is_string_property_value(const property_value *v)
Test if a given property value is a string property value.
Definition abg-ini.cc:341
tuple_property * is_tuple_property(const property *p)
Test if an instance of property is an instance of tuple_property.
Definition abg-ini.cc:757
shared_ptr< tuple_property_value > tuple_property_value_sptr
Convenience typedef for a shared_ptr to a tuple_property_value.
Definition abg-ini.h:170
simple_property * is_simple_property(const property *p)
Tests if a property is a simple property.
Definition abg-ini.cc:619
tuple_property_value * is_tuple_property_value(const property_value *v)
Test if a given instance of property_value is an instance of tuple_property_value too.
Definition abg-ini.cc:525
var_decl_sptr get_last_data_member(const class_or_union &klass)
Get the last data member of a class type.
Definition abg-ir.cc:5781
shared_ptr< function_decl > function_decl_sptr
Convenience typedef for a shared pointer on a function_decl.
Definition abg-fwd.h:269
bool is_type(const type_or_decl_base &tod)
Test whether a declaration is a type.
Definition abg-ir.cc:10807
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition abg-ir.h:926
var_decl_sptr find_last_data_member_matching_regexp(const class_or_union &t, const regex::regex_t_sptr &regex)
Find the last data member of a class or union which name matches a regular expression.
Definition abg-ir.cc:29211
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition abg-ir.cc:11165
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition abg-fwd.h:193
const type_decl * is_type_decl(const type_or_decl_base *t)
Test whether a type is a type_decl (a builtin type).
Definition abg-ir.cc:10909
string get_name(const type_or_decl_base *tod, bool qualified)
Build and return a copy of the name of an ABI artifact that is either a type or a decl.
Definition abg-ir.cc:8686
typedef_decl_sptr is_typedef(const type_or_decl_base_sptr t)
Test whether a type is a typedef.
Definition abg-ir.cc:11011
shared_ptr< function_type > function_type_sptr
Convenience typedef for a shared pointer on a function_type.
Definition abg-fwd.h:210
bool elf_symbol_is_function(elf_symbol::type t)
Test if the type of an ELF symbol denotes a function symbol.
Definition abg-ir.cc:3145
const enum_type_decl * is_enum_type(const type_or_decl_base *d)
Test if a decl is an enum_type_decl.
Definition abg-ir.cc:11100
shared_ptr< var_decl > var_decl_sptr
Convenience typedef for a shared pointer on a var_decl.
Definition abg-fwd.h:256
bool get_data_member_is_laid_out(const var_decl &m)
Test whether a data member is laid out.
Definition abg-ir.cc:6344
bool get_next_data_member_offset(const class_or_union *klass, const var_decl_sptr &dm, uint64_t &offset)
Get the offset of the non-static data member that comes after a given one.
Definition abg-ir.cc:6229
var_decl * is_var_decl(const type_or_decl_base *tod)
Tests if a declaration is a variable declaration.
Definition abg-ir.cc:12059
decl_base * is_decl(const type_or_decl_base *d)
Test if an ABI artifact is a declaration.
Definition abg-ir.cc:10747
uint64_t get_data_member_offset(const var_decl &m)
Get the offset of a data member.
Definition abg-ir.cc:6184
location get_location(const type_base_sptr &type)
Get the location of the declaration of a given type.
Definition abg-ir.cc:8766
bool is_union_type(const type_or_decl_base &t)
Test if a type is a union_decl.
Definition abg-ir.cc:11445
type_base_sptr peel_typedef_type(const type_base_sptr &type)
Return the leaf underlying type node of a typedef_decl node.
Definition abg-ir.cc:7063
var_decl_sptr find_first_data_member_matching_regexp(const class_or_union &t, const regex::regex_t_sptr &r)
Find the first data member of a class or union which name matches a regular expression.
Definition abg-ir.cc:29190
const decl_base * get_type_declaration(const type_base *t)
Get the declaration for a given type.
Definition abg-ir.cc:10229
var_decl_sptr has_flexible_array_data_member(const class_decl &klass)
Test if the last data member of a class is an array with non-finite data member.
Definition abg-ir.cc:11206
array_type_def * is_array_type(const type_or_decl_base *type, bool look_through_qualifiers)
Test if a type is an array_type_def.
Definition abg-ir.cc:12123
function_decl * is_function_decl(const type_or_decl_base *d)
Test whether a declaration is a function_decl.
Definition abg-ir.cc:10695
bool elf_symbol_is_variable(elf_symbol::type t)
Test if the type of an ELF symbol denotes a function symbol.
Definition abg-ir.cc:3155
method_type_sptr is_method_type(const type_or_decl_base_sptr &t)
Test whether a type is a method_type.
Definition abg-ir.cc:11888
string build_qualified_name(const scope_decl *scope, const string &name)
Build and return a qualified name from a name and its scope.
Definition abg-ir.cc:8732
bool match(const regex_t_sptr &r, const std::string &str)
See if a string matches a regex.
Definition abg-regex.cc:127
regex_t_sptr compile(const std::string &str)
Compile a regex from a string.
Definition abg-regex.cc:111
std::shared_ptr< regex_t > regex_t_sptr
A convenience typedef for a shared pointer of regex_t.
Definition abg-fwd.h:87
type_suppression::insertion_range::fn_call_expr_boundary_sptr is_fn_call_expr_boundary(type_suppression::insertion_range::boundary_sptr b)
Tests if a given instance of type_suppression::insertion_range::boundary is actually a function call ...
bool suppression_matches_type(const suppr::type_suppression &s, const string &type_name)
Test if a type suppression matches a type designated by its fully qualified name.
type_suppression::insertion_range::integer_boundary_sptr is_integer_boundary(type_suppression::insertion_range::boundary_sptr b)
Tests if a given instance of type_suppression::insertion_range::boundary is actually an integer bound...
shared_ptr< variable_suppression > variable_suppression_sptr
A convenience typedef for a shared pointer to variable_suppression.
shared_ptr< negated_suppression_base > negated_suppression_sptr
A convenience typedef for a shared pointer to negated_suppression_base.
const char * get_opaque_types_suppr_spec_label()
shared_ptr< file_suppression > file_suppression_sptr
A convenience typedef for a shared_ptr to file_suppression.
vector< suppression_sptr > suppressions_type
Convenience typedef for a vector of suppression_sptr.
Definition abg-fwd.h:1687
type_suppression::insertion_range::named_boundary_sptr is_named_boundary(type_suppression::insertion_range::boundary_sptr b)
Test if a given instance of type_suppression::insertion_range::boundary is actually a named boundary.
shared_ptr< function_suppression > function_suppression_sptr
Convenience typedef for a shared pointer to function_suppression.
variable_suppression_sptr is_variable_suppression(const suppression_sptr s)
Test if an instance of suppression is an instance of variable_suppression.
bool is_opaque_type_suppr_spec(const type_suppression &s)
Test if a type suppression specification represents a private type suppression automatically generate...
bool variable_is_suppressed(const suppr::suppressions_type &supprs, const string &var_name, const string &var_linkage_name, bool require_drop_property)
Test if a given variable is suppressed by at least one suppression specification among a vector of su...
bool suppression_can_match(const fe_iface &fe, const suppression_base &s)
Test if a given suppression specification can match an ABI artifact coming from the corpus being anal...
file_suppression_sptr is_file_suppression(const suppression_sptr s)
Test if a given suppression specification is a file suppression specification.
bool is_elf_symbol_suppressed(const fe_iface &fe, const elf_symbol_sptr &symbol)
Test if an ELF symbol is suppressed by at least one of the suppression specifications associated with...
bool suppression_matches_type_name(const suppr::type_suppression &s, const string &type_name)
Test if a type suppression specification matches a type name.
shared_ptr< type_suppression > type_suppression_sptr
Convenience typedef for a shared pointer to type_suppression.
function_suppression_sptr is_function_suppression(const suppression_sptr suppr)
Test if an instance of suppression is an instance of function_suppression.
bool suppression_matches_variable_name(const suppr::variable_suppression &s, const string &var_name)
Test if a variable suppression matches a variable denoted by its name.
bool suppression_matches_soname_or_filename(const string &soname, const string &filename, const suppression_base &suppr)
Test if a given SONAME or file name is matched by a given suppression specification.
type_suppression_sptr is_type_suppression(suppression_sptr suppr)
Test if an instance of suppression is an instance of type_suppression.
bool check_sufficient_props(const char *const *names, size_t count, const ini::config::section &section)
Check if a section has at least one of the given properties.
bool suppression_matches_type_name_or_location(const type_suppression &s, const string &type_name, const location &type_location)
Test if a type suppression matches a type name and location.
bool suppression_matches_type_location(const type_suppression &s, const location &loc)
Test if a type suppression matches a source location.
bool is_data_member_offset_in_range(const var_decl_sptr &dm, const type_suppression::insertion_range_sptr &range, const class_or_union *context)
Test if a data memer offset is in a given insertion range.
bool is_function_suppressed(const fe_iface &fe, const string &fn_name, const string &fn_linkage_name, bool require_drop_property)
Test if a function is matched by at least one suppression specification associated with a given front...
bool suppression_matches_soname(const string &soname, const suppression_base &suppr)
Test if a given SONAME is matched by a given suppression specification.
bool is_type_suppressed(const fe_iface &fe, const string &type_name, const location &type_location, bool &type_is_opaque, bool require_drop_property)
Test if a type is matched by at least one suppression specification associated with a given front-end...
shared_ptr< suppression_base > suppression_sptr
Convenience typedef for a shared pointer to a suppression.
Definition abg-fwd.h:1684
bool is_negated_suppression(const suppression_base &s)
Test if a suppression specification is a negated suppression.
bool suppression_matches_variable_sym_name(const suppr::variable_suppression &s, const string &var_linkage_name)
Test if a variable suppression matches a variable denoted by its symbol name.
file_suppression_sptr file_is_suppressed(const string &file_path, const suppressions_type &sprs)
Test if a given file path is "suppressed" by at least one file suppression specification among a vect...
bool is_variable_suppressed(const fe_iface &fe, const string &var_name, const string &var_linkage_name, bool require_drop_property)
Test if a variable is matched by at least one suppression specification associated with a given front...
bool base_name(string const &path, string &file_name)
Return the file name part of a file part.
Toplevel namespace for libabigail.
The type of the private data of the function_suppression type.
The type of the private data of the variable_suppression type.