• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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