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