1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2016-2020 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 
18 // <headers defining libabigail's API go under here>
19 ABG_BEGIN_EXPORT_DECLARATIONS
20 
21 #include "abg-ini.h"
22 #include "abg-comp-filter.h"
23 #include "abg-suppression.h"
24 #include "abg-tools-utils.h"
25 
26 ABG_END_EXPORT_DECLARATIONS
27 // </headers defining libabigail's API>
28 
29 #include "abg-suppression-priv.h"
30 
31 namespace abigail
32 {
33 
34 namespace suppr
35 {
36 
37 using std::dynamic_pointer_cast;
38 using regex::regex_t_sptr;
39 
40 // <parsing stuff>
41 
42 // section parsing
43 
44 /// Check if a section has at least one of the given properties.
45 ///
46 /// @param names pointer to the start of an array of names.
47 ///
48 /// @param count number of names in the array.
49 ///
50 /// @return whether at least of one the properties was found.
51 bool
check_sufficient_props(const char * const * names,size_t count,const ini::config::section & section)52 check_sufficient_props(const char *const * names, size_t count,
53 		       const ini::config::section& section)
54 {
55   for (const char *const * name = names; name < names + count; ++name)
56     if (section.find_property(*name))
57       return true;
58   // TODO: Possibly give reason for failure in a message here.
59   return false;
60 }
61 
62 // </parsing stuff>
63 
64 // <suppression_base stuff>
65 
66 /// Constructor for @ref suppression_base
67 ///
68 /// @param a label for the suppression.  This represents just a
69 /// comment.
suppression_base(const string & label)70 suppression_base::suppression_base(const string& label)
71   : priv_(new priv(label))
72 {}
73 
74 /// Constructor for @ref suppression_base
75 ///
76 /// @param a label for the suppression.  This represents just a
77 /// comment.
78 ///
79 /// @param file_name_regex_str the regular expression that denotes the
80 /// file name to match.
81 ///
82 /// @param file_name_not_regex_str the regular expression that denotes
83 /// the file name to *NOT* match.
suppression_base(const string & label,const string & file_name_regex_str,const string & file_name_not_regex_str)84 suppression_base::suppression_base(const string& label,
85 				   const string& file_name_regex_str,
86 				   const string& file_name_not_regex_str)
87   : priv_(new priv(label,
88 		   file_name_regex_str,
89 		   file_name_not_regex_str))
90 {
91 }
92 
93 /// Tests if the current suppression specification is to avoid adding
94 /// the matched ABI artifact to the internal representation or not.
95 ///
96 /// @return true iff the current suppression specification is to avoid
97 /// adding the matched ABI artifact to the internal representation.
98 bool
get_drops_artifact_from_ir() const99 suppression_base::get_drops_artifact_from_ir() const
100 {return priv_->drops_artifact_;}
101 
102 /// Set the flag that says whether the current suppression
103 /// specification is to avoid adding the matched ABI artifact to the
104 /// internal representation or not.
105 ///
106 /// @param f the flag to set to true iff the current suppression
107 /// specification is to avoid adding the matched ABI artifact to the
108 /// internal representation.
109 void
set_drops_artifact_from_ir(bool f)110 suppression_base::set_drops_artifact_from_ir(bool f)
111 {priv_->drops_artifact_ = f;}
112 
113 /// Test is the suppression specification is artificial.
114 ///
115 /// Artificial means that the suppression was automatically generated
116 /// by libabigail, rather than being constructed from a suppression
117 /// file provided by the user.
118 ///
119 /// @return TRUE iff the suppression specification is artificial.
120 bool
get_is_artificial() const121 suppression_base::get_is_artificial() const
122 {return priv_->is_artificial_;}
123 
124 /// Set a flag saying if the suppression specification is artificial
125 /// or not.
126 ///
127 /// Artificial means that the suppression was automatically generated
128 /// by libabigail, rather than being constructed from a suppression
129 /// file provided by the user.
130 void
set_is_artificial(bool f)131 suppression_base::set_is_artificial(bool f)
132 {priv_->is_artificial_ = f;}
133 
134 /// Getter for the label associated to this suppression specification.
135 ///
136 /// @return the label.
137 const string
get_label() const138 suppression_base::get_label() const
139 {return priv_->label_;}
140 
141 /// Setter for the label associated to this suppression specification.
142 ///
143 /// @param label the new label.
144 void
set_label(const string & label)145 suppression_base::set_label(const string& label)
146 {priv_->label_ = label;}
147 
148 /// Setter for the "file_name_regex" property of the current instance
149 /// of @ref suppression_base.
150 ///
151 /// The "file_name_regex" property is a regular expression string that
152 /// designates the file name that contains the ABI artifact this
153 /// suppression should apply to.
154 ///
155 /// @param regexp the new regular expression string.
156 void
set_file_name_regex_str(const string & regexp)157 suppression_base::set_file_name_regex_str(const string& regexp)
158 {priv_->file_name_regex_str_ = regexp;}
159 
160 /// Getter for the "file_name_regex" property of the current instance
161 /// of @ref suppression_base.
162 ///
163 /// The "file_name_regex" property is a regular expression string that
164 /// designates the file name that contains the ABI artifacts this
165 /// suppression should apply to.
166 ///
167 /// @return the regular expression string.
168 const string&
get_file_name_regex_str() const169 suppression_base::get_file_name_regex_str() const
170 {return priv_->file_name_regex_str_;}
171 
172 /// Setter for the "file_name_not_regex" property of the current
173 /// instance of @ref suppression_base.
174 ///
175 /// The current suppression specification should apply to ABI
176 /// artifacts of a file which name does *NOT* match the regular
177 /// expression string designated by the "file_name_not_regex"
178 /// property.
179 ///
180 /// @param regexp the new regular expression string.
181 void
set_file_name_not_regex_str(const string & regexp)182 suppression_base::set_file_name_not_regex_str(const string& regexp)
183 {priv_->file_name_not_regex_str_ = regexp;}
184 
185 /// Getter for the "file_name_not_regex" property of the current
186 /// instance of @ref suppression_base.
187 ///
188 /// The current suppression specification should apply to ABI
189 /// artifacts of a file which name does *NOT* match the regular
190 /// expression string designated by the "file_name_not_regex"
191 /// property.
192 ///
193 /// @return the regular expression string.
194 const string&
get_file_name_not_regex_str() const195 suppression_base::get_file_name_not_regex_str() const
196 {return priv_->file_name_not_regex_str_;}
197 
198 /// Test if the current suppression has a property related to file
199 /// name.
200 ///
201 /// @return true iff the current suppression has either a
202 /// file_name_regex or a file_name_not_regex property.
203 bool
has_file_name_related_property() const204 suppression_base::has_file_name_related_property() const
205 {
206   return (!(get_file_name_regex_str().empty()
207 	    && get_file_name_not_regex_str().empty()));
208 }
209 
210 /// Setter of the "soname_regex_str property of the current instance
211 /// of @ref suppression_base.
212 ///
213 /// The "soname_regex_str" is a regular expression string that
214 /// designates the soname of the shared library that contains the ABI
215 /// artifacts this suppression should apply to.
216 ///
217 /// @param regexp the new regular expression string.
218 void
set_soname_regex_str(const string & regexp)219 suppression_base::set_soname_regex_str(const string& regexp)
220 {priv_->soname_regex_str_ = regexp;}
221 
222 /// Getter of the "soname_regex_str property of the current instance
223 /// of @ref suppression_base.
224 ///
225 /// The "soname_regex_str" is a regular expression string that
226 /// designates the soname of the shared library that contains the ABI
227 /// artifacts this suppression should apply to.
228 ///
229 /// @return the regular expression string.
230 const string&
get_soname_regex_str() const231 suppression_base::get_soname_regex_str() const
232 {return priv_->soname_regex_str_;}
233 
234 /// Setter of the "soname_not_regex_str property of the current
235 /// instance of @ref suppression_base.
236 ///
237 /// The current suppression specification should apply to ABI
238 /// artifacts of a shared library which SONAME does *NOT* match the
239 /// regular expression string designated by the "soname_not_regex"
240 /// property.
241 ///
242 /// @param regexp the new regular expression string.
243 void
set_soname_not_regex_str(const string & regexp)244 suppression_base::set_soname_not_regex_str(const string& regexp)
245 {priv_->soname_not_regex_str_ = regexp;}
246 
247 /// Getter of the "soname_not_regex_str property of the current
248 /// instance of @ref suppression_base.
249 ///
250 /// The current suppression specification should apply to ABI
251 /// artifacts of a shared library which SONAME does *NOT* match the
252 /// regular expression string designated by the "soname_not_regex"
253 /// property.
254 ///
255 /// @return the regular expression string.
256 const string&
get_soname_not_regex_str() const257 suppression_base::get_soname_not_regex_str() const
258 {return priv_->soname_not_regex_str_;}
259 
260 /// Test if the current suppression has a property related to SONAMEs.
261 ///
262 /// @return true iff the current suppression has either a soname_regex
263 /// or a soname_not_regex property.
264 bool
has_soname_related_property() const265 suppression_base::has_soname_related_property() const
266 {
267   return (!(get_soname_regex_str().empty()
268 	    && get_soname_not_regex_str().empty()));
269 }
270 
271 /// Check if the SONAMEs of the two binaries being compared match the
272 /// content of the properties "soname_regexp" and "soname_not_regexp"
273 /// of the current suppression specification.
274 ///
275 /// @param suppr the suppression specification
276 ///
277 /// @param ctxt the context of the comparison.
278 ///
279 /// @return false if the regular expression contained in the property
280 /// soname_regexp or in the property "soname_not_regexp" does *NOT*
281 /// match at least one of the SONAMEs of the two binaries being
282 /// compared.  Return true otherwise.
283 static bool
sonames_of_binaries_match(const suppression_base & suppr,const diff_context & ctxt)284 sonames_of_binaries_match(const suppression_base& suppr,
285 			  const diff_context& ctxt)
286 {
287   // Check if the sonames of the binaries match
288   string first_soname = ctxt.get_corpus_diff()->first_corpus()->get_soname(),
289     second_soname = ctxt.get_corpus_diff()->second_corpus()->get_soname();
290 
291   if (!suppr.has_soname_related_property())
292     return false;
293 
294   if (!suppr.priv_->matches_soname(first_soname)
295       && !suppr.priv_->matches_soname(second_soname))
296     return false;
297 
298   return true;
299 }
300 
301 /// Check if the names of the two binaries being compared match the
302 /// content of the properties "file_name_regexp" and
303 /// "file_name_not_regexp".
304 ///
305 /// @param suppr the current suppression specification.
306 ///
307 /// @param ctxt the context of the comparison.
308 ///
309 /// @return false if the regular expression contained in the property
310 /// file_name_regexp or in the property "file_name_not_regexp" does
311 /// *NOT* match at least one of the names of the two binaries being
312 /// compared.  Return true otherwise.
313 static bool
names_of_binaries_match(const suppression_base & suppr,const diff_context & ctxt)314 names_of_binaries_match(const suppression_base& suppr,
315 			const diff_context &ctxt)
316 {
317    // Check if the file names of the binaries match
318   string first_binary_path = ctxt.get_corpus_diff()->first_corpus()->get_path(),
319     second_binary_path = ctxt.get_corpus_diff()->second_corpus()->get_path();
320 
321   if (!suppr.has_file_name_related_property())
322     return false;
323 
324   if (!suppr.priv_->matches_binary_name(first_binary_path)
325       && !suppr.priv_->matches_binary_name(second_binary_path))
326     return false;
327 
328   return true;
329 }
330 
~suppression_base()331 suppression_base::~suppression_base()
332 {}
333 
334 static type_suppression_sptr
335 read_type_suppression(const ini::config::section& section);
336 
337 static function_suppression_sptr
338 read_function_suppression(const ini::config::section& section);
339 
340 static variable_suppression_sptr
341 read_variable_suppression(const ini::config::section& section);
342 
343 static file_suppression_sptr
344 read_file_suppression(const ini::config::section& section);
345 
346 /// Read a vector of suppression specifications from the sections of
347 /// an ini::config.
348 ///
349 /// Note that this function needs to be updated each time a new kind
350 /// of suppression specification is added.
351 ///
352 /// @param config the config to read from.
353 ///
354 /// @param suppressions out parameter.  The vector of suppressions to
355 /// append the newly read suppressions to.
356 static void
read_suppressions(const ini::config & config,suppressions_type & suppressions)357 read_suppressions(const ini::config& config,
358 		  suppressions_type& suppressions)
359 {
360   suppression_sptr s;
361   for (ini::config::sections_type::const_iterator i =
362 	 config.get_sections().begin();
363        i != config.get_sections().end();
364        ++i)
365     if ((s = read_type_suppression(**i))
366 	|| (s = read_function_suppression(**i))
367 	|| (s = read_variable_suppression(**i))
368 	|| (s = read_file_suppression(**i)))
369       suppressions.push_back(s);
370 
371 }
372 
373 /// Read suppressions specifications from an input stream.
374 ///
375 /// @param input the input stream to read from.
376 ///
377 /// @param suppressions the vector of suppressions to append the newly
378 /// read suppressions to.
379 void
read_suppressions(std::istream & input,suppressions_type & suppressions)380 read_suppressions(std::istream& input,
381 		  suppressions_type& suppressions)
382 {
383     if (ini::config_sptr config = ini::read_config(input))
384     read_suppressions(*config, suppressions);
385 }
386 
387 /// Read suppressions specifications from an input file on disk.
388 ///
389 /// @param input the path to the input file to read from.
390 ///
391 /// @param suppressions the vector of suppressions to append the newly
392 /// read suppressions to.
393 void
read_suppressions(const string & file_path,suppressions_type & suppressions)394 read_suppressions(const string& file_path,
395 		  suppressions_type& suppressions)
396 {
397   if (ini::config_sptr config = ini::read_config(file_path))
398     read_suppressions(*config, suppressions);
399 }
400 // </suppression_base stuff>
401 
402 // <type_suppression stuff>
403 
404 /// Constructor for @ref type_suppression.
405 ///
406 /// @param label the label of the suppression.  This is just a free
407 /// form comment explaining what the suppression is about.
408 ///
409 /// @param type_name_regexp the regular expression describing the
410 /// types about which diff reports should be suppressed.  If it's an
411 /// empty string, the parameter is ignored.
412 ///
413 /// @param type_name the name of the type about which diff reports
414 /// should be suppressed.  If it's an empty string, the parameter is
415 /// ignored.
416 ///
417 /// Note that parameter @p type_name_regexp and @p type_name_regexp
418 /// should not necessarily be populated.  It usually is either one or
419 /// the other that the user wants.
type_suppression(const string & label,const string & type_name_regexp,const string & type_name)420 type_suppression::type_suppression(const string& label,
421 				   const string& type_name_regexp,
422 				   const string& type_name)
423   : suppression_base(label),
424     priv_(new priv(type_name_regexp,
425 		   type_name,
426 		   /*consider_type_kind=*/false,
427 		   /*type_kind=*/CLASS_TYPE_KIND,
428 		   /*consider_reach_kind=*/false,
429 		   /*reach_kind=*/DIRECT_REACH_KIND))
430 {}
431 
~type_suppression()432 type_suppression::~type_suppression()
433 {}
434 
435 /// Setter for the "type_name_regex" property of the type suppression
436 /// specification.
437 ///
438 /// This sets a regular expression that specifies the family of types
439 /// about which diff reports should be suppressed.
440 ///
441 /// @param name_regex_str the new regular expression to set.
442 void
set_type_name_regex_str(const string & name_regex_str)443 type_suppression::set_type_name_regex_str(const string& name_regex_str)
444 {priv_->type_name_regex_str_ = name_regex_str;}
445 
446 /// Getter for the "type_name_regex" property of the type suppression
447 /// specification.
448 ///
449 /// This returns a regular expression string that specifies the family
450 /// of types about which diff reports should be suppressed.
451 ///
452 /// @return the regular expression string.
453 const string&
get_type_name_regex_str() const454 type_suppression::get_type_name_regex_str() const
455 {return priv_->type_name_regex_str_;}
456 
457 /// Setter for the "type_name_not_regex_str" property of the type
458 /// suppression specification.
459 ///
460 /// This returns a regular expression string that specifies the family
461 /// of types that should be kept after suppression.
462 ///
463 /// @param r the new regexp string.
464 void
set_type_name_not_regex_str(const string & r)465 type_suppression::set_type_name_not_regex_str(const string& r)
466 {priv_->set_type_name_not_regex_str(r);}
467 
468 /// Getter for the "type_name_not_regex_str" property of the type
469 /// suppression specification.
470 ///
471 /// This returns a regular expression string that specifies the family
472 /// of types that should be kept after suppression.
473 ///
474 /// @return the new regexp string.
475 const string&
get_type_name_not_regex_str() const476 type_suppression::get_type_name_not_regex_str() const
477 {return priv_->get_type_name_not_regex_str();}
478 
479 /// Setter for the name of the type about which diff reports should be
480 /// suppressed.
481 ///
482 /// @param name the new type name.
483 void
set_type_name(const string & name)484 type_suppression::set_type_name(const string& name)
485 {priv_->type_name_ = name;}
486 
487 /// Getter for the name of the type about which diff reports should be
488 /// suppressed.
489 ///
490 /// @param return the type name.
491 const string&
get_type_name() const492 type_suppression::get_type_name() const
493 {return priv_->type_name_;}
494 
495 /// Getter of the property that says whether to consider the kind of
496 /// type this suppression is about.
497 ///
498 /// @return the boolean value of the property.
499 bool
get_consider_type_kind() const500 type_suppression::get_consider_type_kind() const
501 {return priv_->consider_type_kind_;}
502 
503 /// Setter of the property that says whether to consider the kind of
504 /// type this suppression is about.
505 ///
506 /// @param f the new boolean value of the property.
507 void
set_consider_type_kind(bool f)508 type_suppression::set_consider_type_kind(bool f)
509 {priv_->consider_type_kind_ = f;}
510 
511 /// Setter of the kind of type this suppression is about.
512 ///
513 /// Note that this will be considered during evaluation of the
514 /// suppression only if type_suppression::get_consider_type_kind()
515 /// returns true.
516 ///
517 /// @param k the new kind of type this suppression is about.
518 void
set_type_kind(type_kind k)519 type_suppression::set_type_kind(type_kind k)
520 {priv_->type_kind_ = k;}
521 
522 /// Getter of the kind of type this suppression is about.
523 ///
524 /// Note that this will be considered during evaluation of the
525 /// suppression only if type_suppression::get_consider_type_kind()
526 /// returns true.
527 ///
528 /// @return the kind of type this suppression is about.
529 type_suppression::type_kind
get_type_kind() const530 type_suppression::get_type_kind() const
531 {return priv_->type_kind_;}
532 
533 /// Test if the current type suppression specification
534 /// suggests to consider how the matching diff node is reached.
535 ///
536 /// @return true if the current type suppression specification
537 /// suggests to consider how the matching diff node is reached.
538 bool
get_consider_reach_kind() const539 type_suppression::get_consider_reach_kind() const
540 {return priv_->consider_reach_kind_;}
541 
542 /// Set a flag saying if the current type suppression specification
543 /// suggests to consider how the matching diff node is reached.
544 ///
545 /// @param f the new value of the flag.  It's true iff the current
546 /// type suppression specification suggests to consider how the
547 /// matching diff node is reached.
548 void
set_consider_reach_kind(bool f)549 type_suppression::set_consider_reach_kind(bool f)
550 {priv_->consider_reach_kind_ = f;}
551 
552 /// Getter of the way the diff node matching the current suppression
553 /// specification is to be reached.
554 ///
555 /// @return the way the diff node matching the current suppression
556 /// specification is to be reached.
557 type_suppression::reach_kind
get_reach_kind() const558 type_suppression::get_reach_kind() const
559 {return priv_->reach_kind_;}
560 
561 /// Setter of the way the diff node matching the current suppression
562 /// specification is to be reached.
563 ///
564 /// @param p the way the diff node matching the current suppression
565 /// specification is to be reached.
566 void
set_reach_kind(reach_kind k)567 type_suppression::set_reach_kind(reach_kind k)
568 {priv_->reach_kind_ = k;}
569 
570 /// Setter for the vector of data member insertion ranges that
571 /// specifies where a data member is inserted as far as this
572 /// suppression specification is concerned.
573 ///
574 /// @param r the new insertion range vector.
575 void
set_data_member_insertion_ranges(const insertion_ranges & r)576 type_suppression::set_data_member_insertion_ranges(const insertion_ranges& r)
577 {priv_->insertion_ranges_ = r;}
578 
579 /// Getter for the vector of data member insertion range that
580 /// specifiers where a data member is inserted as far as this
581 /// suppression specification is concerned.
582 ///
583 /// @return the vector of insertion ranges.
584 const type_suppression::insertion_ranges&
get_data_member_insertion_ranges() const585 type_suppression::get_data_member_insertion_ranges() const
586 {return priv_->insertion_ranges_;}
587 
588 /// Getter for the vector of data member insertion range that
589 /// specifiers where a data member is inserted as far as this
590 /// suppression specification is concerned.
591 ///
592 /// @return the vector of insertion ranges.
593 type_suppression::insertion_ranges&
get_data_member_insertion_ranges()594 type_suppression::get_data_member_insertion_ranges()
595 {return priv_->insertion_ranges_;}
596 
597 /// Getter for the array of source location paths of types that should
598 /// *NOT* be suppressed.
599 ///
600 /// @return the set of source locations of types that should *NOT* be
601 /// supressed.
602 const unordered_set<string>&
get_source_locations_to_keep() const603 type_suppression::get_source_locations_to_keep() const
604 {return priv_->source_locations_to_keep_;}
605 
606 /// Getter for the array of source location paths of types that should
607 /// *NOT* be suppressed.
608 ///
609 /// @return the array of source locations of types that should *NOT*
610 /// be supressed.
611 unordered_set<string>&
get_source_locations_to_keep()612 type_suppression::get_source_locations_to_keep()
613 {return priv_->source_locations_to_keep_;}
614 
615 /// Setter for the array of source location paths of types that should
616 /// *NOT* be suppressed.
617 ///
618 /// @param l the new array.
619 void
set_source_locations_to_keep(const unordered_set<string> & l)620 type_suppression::set_source_locations_to_keep
621 (const unordered_set<string>& l)
622 {priv_->source_locations_to_keep_ = l;}
623 
624 /// Getter of the regular expression string that designates the source
625 /// location paths of types that should not be suppressed.
626 ///
627 /// @return the regular expression string.
628 const string&
get_source_location_to_keep_regex_str() const629 type_suppression::get_source_location_to_keep_regex_str() const
630 {return priv_->source_location_to_keep_regex_str_;}
631 
632 /// Setter of the regular expression string that designates the source
633 /// location paths of types that should not be suppressed.
634 ///
635 /// @param r the new regular expression.
636 void
set_source_location_to_keep_regex_str(const string & r)637 type_suppression::set_source_location_to_keep_regex_str(const string& r)
638 {priv_->source_location_to_keep_regex_str_ = r;}
639 
640 /// Getter of the vector of the changed enumerators that are supposed
641 /// to be suppressed.  Note that this will be "valid" only if the type
642 /// suppression has the 'type_kind = enum' property.
643 ///
644 /// @return the vector of the changed enumerators that are supposed to
645 /// be suppressed.
646 const vector<string>&
get_changed_enumerator_names() const647 type_suppression::get_changed_enumerator_names() const
648 {return priv_->changed_enumerator_names_;}
649 
650 /// Setter of the vector of changed enumerators that are supposed to
651 /// be suppressed.  Note that this will be "valid" only if the type
652 /// suppression has the 'type_kind = enum' property.
653 ///
654 /// @param n the vector of the changed enumerators that are supposed
655 /// to be suppressed.
656 void
set_changed_enumerator_names(const vector<string> & n)657 type_suppression::set_changed_enumerator_names(const vector<string>& n)
658 {priv_->changed_enumerator_names_ = n;}
659 
660 /// Evaluate this suppression specification on a given diff node and
661 /// say if the diff node should be suppressed or not.
662 ///
663 /// @param diff the diff node to evaluate this suppression
664 /// specification against.
665 ///
666 /// @return true if @p diff should be suppressed.
667 bool
suppresses_diff(const diff * diff) const668 type_suppression::suppresses_diff(const diff* diff) const
669 {
670   const type_diff_base* d = is_type_diff(diff);
671   if (!d)
672     {
673       // So the diff we are looking at is not a type diff.  However,
674       // there are cases where a type suppression can suppress changes
675       // on functions.
676 
677       // Typically, if a virtual member function's virtual index (its
678       // index in the vtable of a class) changes and if the current
679       // type suppression is meant to suppress change reports about
680       // the enclosing class of the virtual member function, then this
681       // type suppression should suppress reports about that function
682       // change.
683       const function_decl_diff* d = is_function_decl_diff(diff);
684       if (d)
685 	{
686 	  // Let's see if 'd' carries a virtual member function
687 	  // change.
688 	  if (comparison::filtering::has_virtual_mem_fn_change(d))
689 	    {
690 	      function_decl_sptr f = d->first_function_decl();
691 	      class_decl_sptr fc =
692 		is_class_type(is_method_type(f->get_type())->get_class_type());
693 	      ABG_ASSERT(fc);
694 	      if (suppresses_type(fc, diff->context()))
695 		return true;
696 	    }
697 	}
698       return false;
699     }
700 
701   // If the suppression should consider the way the diff node has been
702   // reached, then do it now.
703   if (get_consider_reach_kind())
704     {
705       if (get_reach_kind() == POINTER_REACH_KIND)
706 	{
707 	  if (const pointer_diff* ptr_diff = is_pointer_diff(diff))
708 	    {
709 	      d = is_type_diff(ptr_diff->underlying_type_diff().get());
710 	      if (!d)
711 		// This might be of, e.g, distinct_diff type.
712 		return false;
713 	      d = is_type_diff(peel_qualified_diff(d));
714 	    }
715 	  else
716 	    return false;
717 	}
718       else if (get_reach_kind() == REFERENCE_REACH_KIND)
719 	{
720 	  if (const reference_diff* ref_diff = is_reference_diff(diff))
721 	    {
722 	      d = is_type_diff(ref_diff->underlying_type_diff().get());
723 	      if (!d)
724 		// This might be of, e.g, distinct_diff type.
725 		return false;
726 	      d = is_type_diff(peel_qualified_diff(d));
727 	    }
728 	  else
729 	    return false;
730 	}
731       else if (get_reach_kind() == REFERENCE_OR_POINTER_REACH_KIND)
732 	{
733 	  if (const pointer_diff* ptr_diff = is_pointer_diff(diff))
734 	    {
735 	      d = is_type_diff(ptr_diff->underlying_type_diff().get());
736 	      ABG_ASSERT(d);
737 	      d = is_type_diff(peel_qualified_diff(d));
738 	    }
739 	  else if (const reference_diff* ref_diff = is_reference_diff(diff))
740 	    {
741 	      d = is_type_diff(ref_diff->underlying_type_diff().get());
742 	      ABG_ASSERT(d);
743 	      d = is_type_diff(peel_qualified_diff(d));
744 	    }
745 	  else
746 	    return false;
747 	}
748     }
749 
750   type_base_sptr ft, st;
751   ft = is_type(d->first_subject());
752   st = is_type(d->second_subject());
753   ABG_ASSERT(ft && st);
754 
755   if (!suppresses_type(ft, d->context())
756       && !suppresses_type(st, d->context()))
757     {
758       // A private type suppression specification considers that a
759       // type can be private and yet some typedefs of that type can be
760       // public -- depending on, e.g, if the typedef is defined in a
761       // public header or not.  So if we are in the context of a
762       // private type suppression let's *NOT* peel typedefs away.
763       if (!is_private_type_suppr_spec(*this))
764 	{
765 	  ft = peel_typedef_type(ft);
766 	  st = peel_typedef_type(st);
767 	}
768 
769       if (!suppresses_type(ft, d->context())
770 	  && !suppresses_type(st, d->context()))
771 	return false;
772 
773       d = is_type_diff(get_typedef_diff_underlying_type_diff(d));
774     }
775 
776   const class_diff* klass_diff = dynamic_cast<const class_diff*>(d);
777   if (// We are looking at a class diff ...
778       klass_diff
779       // ... that has inserted data members ...
780       && !get_data_member_insertion_ranges().empty()
781       // ... that has no deleted data members ...
782       && klass_diff->deleted_data_members().empty()
783       // ... and in which the class size hasn't shrunk (because, e.g,
784       // the base classes have changed).
785       && (klass_diff->first_class_decl()->get_size_in_bits()
786 	  <= klass_diff->second_class_decl()->get_size_in_bits()))
787     {
788       const class_decl_sptr& first_type_decl = klass_diff->first_class_decl();
789       const class_decl_sptr& second_type_decl = klass_diff->second_class_decl();
790       size_t first_type_size = first_type_decl->get_size_in_bits();
791       size_t second_type_size = second_type_decl->get_size_in_bits();
792 
793       for (string_decl_base_sptr_map::const_iterator m =
794 	     klass_diff->inserted_data_members().begin();
795 	   m != klass_diff->inserted_data_members().end();
796 	   ++m)
797 	{
798 	  decl_base_sptr member = m->second;
799 	  size_t dm_offset = get_data_member_offset(member);
800 	  bool matched = false;
801 
802 	  for (insertion_ranges::const_iterator i =
803 		 get_data_member_insertion_ranges().begin();
804 	       i != get_data_member_insertion_ranges().end();
805 	       ++i)
806 	    {
807 	      type_suppression::insertion_range_sptr range = *i;
808 	      ssize_t range_begin_val = 0,range_end_val = 0;
809 	      if (!type_suppression::insertion_range::eval_boundary
810 		  (range->begin(), first_type_decl, range_begin_val))
811 		break;
812 	      if (!type_suppression::insertion_range::eval_boundary
813 		  (range->end(), first_type_decl, range_end_val))
814 		break;
815 
816 	      unsigned range_begin =
817 		(range_begin_val < 0) ? first_type_size : range_begin_val;
818 
819 	      unsigned range_end =
820 		(range_end_val < 0) ? second_type_size : range_end_val;
821 
822 	      if (range_begin > range_end)
823 		continue;
824 
825 	      if (range_begin_val < 0 || range_end_val < 0)
826 		{
827 		  if (dm_offset < range_begin)
828 		    continue;
829 		}
830 	      else
831 		if (dm_offset < range_begin || dm_offset > range_end)
832 		  continue;
833 
834 	      matched = true;
835 	    }
836 	  if (!matched)
837 	    return false;
838 	}
839     }
840 
841   const enum_diff* enum_dif = dynamic_cast<const enum_diff*>(d);
842   if (// We are looking at an enum diff node which ...
843       enum_dif
844       //... carries no deleted enumerator ... "
845       && enum_dif->deleted_enumerators().empty()
846       // ... carries no size change ...
847       && (enum_dif->first_enum()->get_size_in_bits()
848 	  == enum_dif->second_enum()->get_size_in_bits())
849       // ... and yet carries some changed enumerators!
850       && !enum_dif->changed_enumerators().empty())
851     {
852       // Make sure that all changed enumerators are listed in the
853       // vector of enumerator names returned by the
854       // get_changed_enumerator_names() member function.
855       bool matched = true;
856       for (string_changed_enumerator_map::const_iterator i =
857 	     enum_dif->changed_enumerators().begin();
858 	   i != enum_dif->changed_enumerators().end();
859 	   ++i)
860 	{
861 	  matched &= true;
862 	  if (std::find(get_changed_enumerator_names().begin(),
863 			get_changed_enumerator_names().end(),
864 			i->first) == get_changed_enumerator_names().end())
865 	    {
866 	      matched &= false;
867 	      break;
868 	    }
869 	}
870       if (!matched)
871 	return false;
872     }
873 
874   return true;
875 }
876 
877 /// Test if the current instance of @ref type_suppression suppresses a
878 /// change reports about a given type.
879 ///
880 /// @param type the type to consider.
881 ///
882 /// @param ctxt the context of comparison we are involved with.
883 ///
884 /// @return true iff the suppression specification suppresses type @p
885 /// type.
886 bool
suppresses_type(const type_base_sptr & type,const diff_context_sptr & ctxt) const887 type_suppression::suppresses_type(const type_base_sptr& type,
888 				  const diff_context_sptr& ctxt) const
889 {
890   if (ctxt)
891     {
892       // Check if the names of the binaries match the suppression
893       if (!names_of_binaries_match(*this, *ctxt))
894 	if (has_file_name_related_property())
895 	  return false;
896 
897       // Check if the sonames of the binaries match the suppression
898       if (!sonames_of_binaries_match(*this, *ctxt))
899 	if (has_soname_related_property())
900 	  return false;
901     }
902 
903   return suppresses_type(type);
904 }
905 
906 /// Test if an instance of @ref type_suppression matches a given type.
907 ///
908 /// This function does not take the name of the type into account
909 /// while testing if the type matches the type_suppression.
910 ///
911 /// @param s the suppression to evaluate.
912 ///
913 /// @param type the type to consider.
914 ///
915 /// @return true iff the suppression specification matches type @p
916 /// type without taking its name into account.
917 static bool
suppression_matches_type_no_name(const type_suppression & s,const type_base_sptr & type)918 suppression_matches_type_no_name(const type_suppression&	 s,
919 				 const type_base_sptr		&type)
920 {
921   // If the suppression should consider type kind then, well, check
922   // for that.
923   if (s.get_consider_type_kind())
924     {
925       type_suppression::type_kind tk = s.get_type_kind();
926       bool matches = true;
927       switch (tk)
928 	{
929 	case type_suppression::UNKNOWN_TYPE_KIND:
930 	case type_suppression::CLASS_TYPE_KIND:
931 	  if (!is_class_type(type))
932 	    matches = false;
933 	  break;
934 	case type_suppression::STRUCT_TYPE_KIND:
935 	  {
936 	    class_decl_sptr klass = is_class_type(type);
937 	    if (!klass || !klass->is_struct())
938 	      matches = false;
939 	  }
940 	  break;
941 	case type_suppression::UNION_TYPE_KIND:
942 	  if (!is_union_type(type))
943 	    matches = false;
944 	  break;
945 	case type_suppression::ENUM_TYPE_KIND:
946 	  if (!is_enum_type(type))
947 	    matches = false;
948 	  break;
949 	case type_suppression::ARRAY_TYPE_KIND:
950 	  if (!is_array_type(type))
951 	    matches = false;
952 	  break;
953 	case type_suppression::TYPEDEF_TYPE_KIND:
954 	  if (!is_typedef(type))
955 	    matches = false;
956 	  break;
957 	case type_suppression::BUILTIN_TYPE_KIND:
958 	  if (!is_type_decl(type))
959 	    matches = false;
960 	  break;
961 	}
962 
963       if (!matches)
964 	return false;
965     }
966 
967   // Check if there is a source location related match.
968   if (!suppression_matches_type_location(s, type))
969     return false;
970 
971   return true;
972 }
973 
974 /// Test if a type suppression specification matches a type name.
975 ///
976 /// @param s the type suppression to consider.
977 ///
978 /// @param type_name the type name to consider.
979 ///
980 /// @return true iff the type designated by its name @p type_name is
981 /// matched by the type suppression specification @p s.
982 bool
suppression_matches_type_name(const type_suppression & s,const string & type_name)983 suppression_matches_type_name(const type_suppression&	s,
984 			      const string&		type_name)
985 {
986   if (!s.get_type_name().empty()
987       || s.priv_->get_type_name_regex()
988       || s.priv_->get_type_name_not_regex())
989     {
990       // Check if there is an exact type name match.
991       if (!s.get_type_name().empty())
992 	{
993 	  if (s.get_type_name() != type_name)
994 	    return false;
995 	}
996       else
997 	{
998 	  // Now check if there is a regular expression match.
999 	  //
1000 	  // If the qualified name of the considered type doesn't match
1001 	  // the regular expression of the type name, then this
1002 	  // suppression doesn't apply.
1003 	  if (const regex_t_sptr& type_name_regex =
1004 	      s.priv_->get_type_name_regex())
1005 	    {
1006 	      if (!regex::match(type_name_regex, type_name))
1007 		return false;
1008 	    }
1009 
1010 	  if (const regex_t_sptr type_name_not_regex =
1011 	      s.priv_->get_type_name_not_regex())
1012 	    {
1013 	      if (regex::match(type_name_not_regex, type_name))
1014 		return false;
1015 	    }
1016 	}
1017     }
1018 
1019   return true;
1020 }
1021 
1022 /// Test if a type suppression matches a type in a particular scope.
1023 ///
1024 /// @param s the type suppression to consider.
1025 ///
1026 /// @param type_scope the scope of the type to consider.
1027 ///
1028 /// @param type the type to consider.
1029 ///
1030 /// @return true iff the supression @p s matches type @p type in scope
1031 /// @p type_scope.
1032 bool
suppression_matches_type_name(const suppr::type_suppression & s,const scope_decl * type_scope,const type_base_sptr & type)1033 suppression_matches_type_name(const suppr::type_suppression&	s,
1034 			      const scope_decl*		type_scope,
1035 			      const type_base_sptr&		type)
1036 {
1037   string type_name = build_qualified_name(type_scope, type);
1038   return suppression_matches_type_name(s, type_name);
1039 }
1040 
1041 /// Test if a type suppression matches a source location.
1042 ///
1043 /// @param s the type suppression to consider.
1044 ///
1045 /// @param loc the location to consider.
1046 ///
1047 /// @return true iff the suppression @p s matches location @p loc.
1048 bool
suppression_matches_type_location(const type_suppression & s,const location & loc)1049 suppression_matches_type_location(const type_suppression&	s,
1050 				  const location&		loc)
1051 {
1052   if (loc)
1053     {
1054       // Check if there is a source location related match.
1055       string loc_path, loc_path_base;
1056       unsigned loc_line = 0, loc_column = 0;
1057       loc.expand(loc_path, loc_line, loc_column);
1058 
1059       if (regex_t_sptr regexp = s.priv_->get_source_location_to_keep_regex())
1060 	if (regex::match(regexp, loc_path))
1061 	  return false;
1062 
1063       tools_utils::base_name(loc_path, loc_path_base);
1064       if (s.get_source_locations_to_keep().find(loc_path_base)
1065 	  != s.get_source_locations_to_keep().end())
1066 	return false;
1067       if (s.get_source_locations_to_keep().find(loc_path)
1068 	  != s.get_source_locations_to_keep().end())
1069 	return false;
1070     }
1071   else
1072     {
1073       if (!s.get_source_locations_to_keep().empty()
1074 	  || s.priv_->get_source_location_to_keep_regex())
1075 	// The user provided a "source_location_not_regexp" or
1076 	// a "source_location_not_in" property that was not
1077 	// triggered.  This means the current type suppression
1078 	// doesn't suppress the type given.
1079 	return false;
1080     }
1081 
1082   return true;
1083 }
1084 
1085 /// Test if a type suppression matches a type.
1086 ///
1087 /// @param s the type suppression to consider.
1088 ///
1089 /// @param type the type to consider.
1090 ///
1091 /// @return true iff the suppression @p s matches type @p type.
1092 bool
suppression_matches_type_location(const type_suppression & s,const type_base_sptr & type)1093 suppression_matches_type_location(const type_suppression&	s,
1094 				  const type_base_sptr&	type)
1095 {
1096   location loc = get_location(type);
1097   if (loc)
1098     return suppression_matches_type_location(s, loc);
1099   else
1100     {
1101       // The type had no source location.
1102       //
1103       // In the case where this type suppression was automatically
1104       // generated to suppress types not defined in public
1105       // headers, then this might mean that the type is not
1106       // defined in the public headers.  Otherwise, why does it
1107       // not have a source location?
1108       if (s.get_is_artificial())
1109 	{
1110 	  if (class_decl_sptr cl = is_class_type(type))
1111 	    {
1112 	      if (cl->get_is_declaration_only())
1113 		// We tried hard above to get the definition of
1114 		// the declaration.  If we reach this place, it
1115 		// means the class has no definition at this point.
1116 		ABG_ASSERT(!cl->get_definition_of_declaration());
1117 	      if (s.get_label() == get_private_types_suppr_spec_label())
1118 		// So this looks like what really amounts to an
1119 		// opaque type.  So it's not defined in the public
1120 		// headers.  So we want to filter it out.
1121 		return true;
1122 	    }
1123 	}
1124       if (!s.get_source_locations_to_keep().empty()
1125 	  || s.priv_->get_source_location_to_keep_regex())
1126 	// The user provided a "source_location_not_regexp" or
1127 	// a "source_location_not_in" property that was not
1128 	// triggered.  This means the current type suppression
1129 	// doesn't suppress the type given.
1130 	return false;
1131     }
1132 
1133   return true;
1134 }
1135 
1136 /// Test if a type suppression matches a type name and location.
1137 ///
1138 /// @param s the type suppression to consider.
1139 ///
1140 /// @param type_name the name of the type to consider.
1141 ///
1142 /// @param type_location the location of the type to consider.
1143 ///
1144 /// @return true iff suppression @p s matches a type named @p
1145 /// type_name with a location @p type_location.
1146 bool
suppression_matches_type_name_or_location(const type_suppression & s,const string & type_name,const location & type_location)1147 suppression_matches_type_name_or_location(const type_suppression& s,
1148 					  const string& type_name,
1149 					  const location& type_location)
1150 {
1151   if (!suppression_matches_type_name(s, type_name))
1152     return false;
1153   if (!suppression_matches_type_location(s, type_location))
1154     return false;
1155   return true;
1156 }
1157 
1158 /// Test if the current instance of @ref type_suppression matches a
1159 /// given type.
1160 ///
1161 /// @param type the type to consider.
1162 ///
1163 /// @return true iff the suppression specification suppresses type @p
1164 /// type.
1165 bool
suppresses_type(const type_base_sptr & type) const1166 type_suppression::suppresses_type(const type_base_sptr& type) const
1167 {
1168   if (!suppression_matches_type_no_name(*this, type))
1169     return false;
1170 
1171   if (!suppression_matches_type_name(*this, get_name(type)))
1172     return false;
1173 
1174   return true;
1175 }
1176 
1177 /// Test if the current instance of @ref type_suppression matches a
1178 /// given type in a given scope.
1179 ///
1180 /// @param type the type to consider.
1181 ///
1182 /// @param type_scope the scope of type @p type.
1183 ///
1184 /// @return true iff the suppression specification suppresses type @p
1185 /// type from scope @p type_scope.
1186 bool
suppresses_type(const type_base_sptr & type,const scope_decl * type_scope) const1187 type_suppression::suppresses_type(const type_base_sptr& type,
1188 				  const scope_decl* type_scope) const
1189 {
1190   if (!suppression_matches_type_no_name(*this, type))
1191     return false;
1192 
1193   if (!suppression_matches_type_name(*this, type_scope, type))
1194     return false;
1195 
1196   return true;
1197 }
1198 
1199 /// The private data of type_suppression::insertion_range
1200 struct type_suppression::insertion_range::priv
1201 {
1202   boundary_sptr begin_;
1203   boundary_sptr end_;
1204 
privabigail::suppr::type_suppression::insertion_range::priv1205   priv()
1206   {}
1207 
privabigail::suppr::type_suppression::insertion_range::priv1208   priv(boundary_sptr begin, boundary_sptr end)
1209     : begin_(begin), end_(end)
1210   {}
1211 }; // end struct type_suppression::insertion_range::priv
1212 
1213 /// Default Constructor of @ref type_suppression::insertion_range.
insertion_range()1214 type_suppression::insertion_range::insertion_range()
1215   : priv_(new priv)
1216 {}
1217 
1218 /// Constructor of @ref type_suppression::insertion_range.
1219 ///
1220 /// @param begin the start of the range.  A range boundary that is an
1221 /// instance of @ref interger_boundary with a negative value means the
1222 /// maximum possible value.
1223 ///
1224 /// @param end the end of the range.  A range boundary that is an
1225 /// instance of @ref interger_boundary with a negative value means the
1226 /// maximum possible value.
insertion_range(boundary_sptr begin,boundary_sptr end)1227 type_suppression::insertion_range::insertion_range(boundary_sptr begin,
1228 						   boundary_sptr end)
1229   : priv_(new priv(begin, end))
1230 {}
1231 
1232 /// Getter for the beginning of the range.
1233 ///
1234 /// @return the beginning of the range.  A range boundary that is an
1235 /// instance of @ref interger_boundary with a negative value means the
1236 /// maximum possible value.
1237 type_suppression::insertion_range::boundary_sptr
begin() const1238 type_suppression::insertion_range::begin() const
1239 {return priv_->begin_;}
1240 
1241 /// Getter for the end of the range.
1242 ///
1243 /// @return the end of the range.  A range boundary that is an
1244 /// instance of @ref interger_boundary with a negative value means the
1245 /// maximum possible value.
1246 type_suppression::insertion_range::boundary_sptr
end() const1247 type_suppression::insertion_range::end() const
1248 {return priv_->end_;}
1249 
1250 /// Create an integer boundary.
1251 ///
1252 /// The return value of this function is to be used as a boundary for
1253 /// an instance of @ref type_suppression::insertion_range.  That
1254 /// boundary evaluates to an integer value.
1255 ///
1256 /// @param value the value of the integer boundary.
1257 ///
1258 /// @return the resulting integer boundary.
1259 type_suppression::insertion_range::integer_boundary_sptr
create_integer_boundary(int value)1260 type_suppression::insertion_range::create_integer_boundary(int value)
1261 {return integer_boundary_sptr(new integer_boundary(value));}
1262 
1263 /// Create a function call expression boundary.
1264 ///
1265 /// The return value of this function is to be used as a boundary for
1266 /// an instance of @ref type_suppression::insertion_range.  The value
1267 /// of that boundary is actually a function call expression that
1268 /// itself evalutates to an integer value, in the context of a @ref
1269 /// class_decl.
1270 ///
1271 /// @param expr the function call expression to create the boundary from.
1272 ///
1273 /// @return the resulting function call expression boundary.
1274 type_suppression::insertion_range::fn_call_expr_boundary_sptr
create_fn_call_expr_boundary(ini::function_call_expr_sptr expr)1275 type_suppression::insertion_range::create_fn_call_expr_boundary(ini::function_call_expr_sptr expr)
1276 {return fn_call_expr_boundary_sptr(new fn_call_expr_boundary(expr));}
1277 
1278 /// Create a function call expression boundary.
1279 ///
1280 /// The return value of this function is to be used as a boundary for
1281 /// an instance of @ref type_suppression::insertion_range.  The value
1282 /// of that boundary is actually a function call expression that
1283 /// itself evalutates to an integer value, in the context of a @ref
1284 /// class_decl.
1285 ///
1286 /// @param s a string representing the expression the function call
1287 /// expression to create the boundary from.
1288 ///
1289 /// @return the resulting function call expression boundary.
1290 type_suppression::insertion_range::fn_call_expr_boundary_sptr
create_fn_call_expr_boundary(const string & s)1291 type_suppression::insertion_range::create_fn_call_expr_boundary(const string& s)
1292 {
1293   fn_call_expr_boundary_sptr result, nil;
1294   ini::function_call_expr_sptr expr;
1295   if (ini::read_function_call_expr(s, expr) && expr)
1296     result.reset(new fn_call_expr_boundary(expr));
1297   return result;
1298 }
1299 
1300 /// Evaluate an insertion range boundary to get a resulting integer
1301 /// value.
1302 ///
1303 /// @param boundary the boundary to evaluate.
1304 ///
1305 /// @param context the context of evualuation.  It's a @ref class_decl
1306 /// to take into account during the evaluation, if there is a need for
1307 /// it.
1308 ///
1309 /// @return true iff the evaluation was successful and @p value
1310 /// contains the resulting value.
1311 bool
eval_boundary(boundary_sptr boundary,class_decl_sptr context,ssize_t & value)1312 type_suppression::insertion_range::eval_boundary(boundary_sptr	 boundary,
1313 						 class_decl_sptr context,
1314 						 ssize_t&	 value)
1315 {
1316   if (integer_boundary_sptr b = is_integer_boundary(boundary))
1317     {
1318       value = b->as_integer();
1319       return true;
1320     }
1321   else if (fn_call_expr_boundary_sptr b = is_fn_call_expr_boundary(boundary))
1322     {
1323       ini::function_call_expr_sptr fn_call = b->as_function_call_expr();
1324       if ((fn_call->get_name() == "offset_of"
1325 	   || fn_call->get_name() == "offset_after")
1326 	  && fn_call->get_arguments().size() == 1)
1327 	{
1328 	  string member_name = fn_call->get_arguments()[0];
1329 	  for (class_decl::data_members::const_iterator it =
1330 		 context->get_data_members().begin();
1331 	       it != context->get_data_members().end();
1332 	       ++it)
1333 	    {
1334 	      if (!get_data_member_is_laid_out(**it))
1335 		continue;
1336 	      if ((*it)->get_name() == member_name)
1337 		{
1338 		  if (fn_call->get_name() == "offset_of")
1339 		    value = get_data_member_offset(*it);
1340 		  else if (fn_call->get_name() == "offset_after")
1341 		    value = get_data_member_offset(*it) +
1342 		      (*it)->get_type()->get_size_in_bits();
1343 		  else
1344 		    // We should not reach this point.
1345 		    abort();
1346 		  return true;
1347 		}
1348 	    }
1349 	}
1350     }
1351   return false;
1352 }
1353 
1354 /// Tests if a given instance of @ref
1355 /// type_suppression::insertion_range::boundary is actually an integer boundary.
1356 ///
1357 /// @param b the boundary to test.
1358 ///
1359 /// @return a pointer to the instance of
1360 /// type_suppression::insertion_range::integer_boundary if @p b is
1361 /// actually an integer boundary.  Otherwise, return a null pointer.
1362 type_suppression::insertion_range::integer_boundary_sptr
is_integer_boundary(type_suppression::insertion_range::boundary_sptr b)1363 is_integer_boundary(type_suppression::insertion_range::boundary_sptr b)
1364 {return dynamic_pointer_cast<type_suppression::insertion_range::integer_boundary>(b);}
1365 
1366 /// Tests if a given instance of @ref
1367 /// type_suppression::insertion_range::boundary is actually an function call expression boundary.
1368 ///
1369 /// @param b the boundary to test.
1370 ///
1371 /// @return a pointer to the instance of
1372 /// type_suppression::insertion_range::fn_call_expr_boundary if @p b
1373 /// is actually an function call expression boundary.  Otherwise,
1374 /// return a null pointer.
1375 type_suppression::insertion_range::fn_call_expr_boundary_sptr
is_fn_call_expr_boundary(type_suppression::insertion_range::boundary_sptr b)1376 is_fn_call_expr_boundary(type_suppression::insertion_range::boundary_sptr b)
1377 {return dynamic_pointer_cast<type_suppression::insertion_range::fn_call_expr_boundary>(b);}
1378 
1379 /// The private data type of @ref
1380 /// type_suppression::insertion_range::boundary.
1381 struct type_suppression::insertion_range::boundary::priv
1382 {
privabigail::suppr::type_suppression::insertion_range::boundary::priv1383   priv()
1384   {}
1385 }; // end struct type_suppression::insertion_range::boundary::priv
1386 
1387 /// Default constructor of @ref
1388 /// type_suppression::insertion_range::boundary
boundary()1389 type_suppression::insertion_range::boundary::boundary()
1390   : priv_(new priv())
1391 {}
1392 
1393 /// Destructor of @ref type_suppression::insertion_range::boundary.
~boundary()1394 type_suppression::insertion_range::boundary::~boundary()
1395 {}
1396 
1397 /// Private data type for @ref
1398 /// type_suppression::insertion_range::integer_boundary.
1399 struct type_suppression::insertion_range::integer_boundary::priv
1400 {
1401   int value_;
1402 
privabigail::suppr::type_suppression::insertion_range::integer_boundary::priv1403   priv()
1404     : value_()
1405   {}
1406 
privabigail::suppr::type_suppression::insertion_range::integer_boundary::priv1407   priv(int value)
1408     : value_(value)
1409   {}
1410 }; // end type_suppression::insertion_range::integer_boundary::priv
1411 
1412 /// Converting constructor of
1413 /// type_suppression::insertion_range::integer_boundary.
1414 ///
1415 /// @param value the integer value of the newly created integer boundary.
integer_boundary(int value)1416 type_suppression::insertion_range::integer_boundary::integer_boundary(int value)
1417   : priv_(new priv(value))
1418 {}
1419 
1420 /// Return the integer value of the current inace of @ref
1421 /// type_suppression::insertion_range::integer_boundary.
1422 ///
1423 /// @return the integer value of the current boundary.
1424 int
as_integer() const1425 type_suppression::insertion_range::integer_boundary::as_integer() const
1426 {return priv_->value_;}
1427 
1428 /// Converts the current boundary into an integer value.
1429 ///
1430 /// @return the integer value of the current boundary.
operator int() const1431 type_suppression::insertion_range::integer_boundary::operator int() const
1432 {return as_integer();}
1433 
1434 /// Destructor of @ref type_suppression::insertion_range::integer_boundary.
~integer_boundary()1435 type_suppression::insertion_range::integer_boundary::~integer_boundary()
1436 {}
1437 
1438 /// Private data type of type @ref
1439 /// type_suppression::insertion_range::fn_call_expr_boundary.
1440 struct type_suppression::insertion_range::fn_call_expr_boundary::priv
1441 {
1442   ini::function_call_expr_sptr expr_;
1443 
privabigail::suppr::type_suppression::insertion_range::fn_call_expr_boundary::priv1444   priv()
1445   {}
1446 
privabigail::suppr::type_suppression::insertion_range::fn_call_expr_boundary::priv1447   priv(ini::function_call_expr_sptr expr)
1448     : expr_(expr)
1449   {}
1450 }; // end struct type_suppression::insertion_range::fn_call_expr_boundary::priv
1451 
1452 /// Converting constructor for @ref
1453 /// type_suppression::insertion_range::fn_call_expr_boundary.
1454 ///
1455 /// @param expr the function call expression to build this boundary
1456 /// from.
1457 type_suppression::insertion_range::fn_call_expr_boundary::
fn_call_expr_boundary(ini::function_call_expr_sptr expr)1458 fn_call_expr_boundary(ini::function_call_expr_sptr expr)
1459   : priv_(new priv(expr))
1460 {}
1461 
1462 /// Returns the function call expression value of the current boundary.
1463 ///
1464 /// @return the function call expression value of the current boundary;
1465 ini::function_call_expr_sptr
as_function_call_expr() const1466 type_suppression::insertion_range::fn_call_expr_boundary::as_function_call_expr() const
1467 {return priv_->expr_;}
1468 
1469 /// Converts the current boundary to its function call expression value.
1470 ///
1471 /// @return the function call expression value of the current boundary.
operator ini::function_call_expr_sptr() const1472 type_suppression::insertion_range::fn_call_expr_boundary::operator ini::function_call_expr_sptr () const
1473 {return as_function_call_expr();}
1474 
1475 /// Destructor of @ref
1476 /// type_suppression::insertion_range::fn_call_expr_boundary.
~fn_call_expr_boundary()1477 type_suppression::insertion_range::fn_call_expr_boundary::~fn_call_expr_boundary()
1478 {}
1479 
1480 /// Test if an instance of @ref suppression is an instance of @ref
1481 /// type_suppression.
1482 ///
1483 /// @param suppr the instance of @ref suppression to test for.
1484 ///
1485 /// @return if @p suppr is an instance of @ref type_suppression, then
1486 /// return the sub-object of the @p suppr of type @ref
1487 /// type_suppression, otherwise return a nil pointer.
1488 type_suppression_sptr
is_type_suppression(suppression_sptr suppr)1489 is_type_suppression(suppression_sptr suppr)
1490 {return dynamic_pointer_cast<type_suppression>(suppr);}
1491 
1492 // </type_suppression stuff>
1493 
1494 /// Parse the value of the "type_kind" property in the "suppress_type"
1495 /// section.
1496 ///
1497 /// @param input the input string representing the value of the
1498 /// "type_kind" property.
1499 ///
1500 /// @return the @ref type_kind enumerator parsed.
1501 static type_suppression::type_kind
read_type_kind_string(const string & input)1502 read_type_kind_string(const string& input)
1503 {
1504   if (input == "class")
1505     return type_suppression::CLASS_TYPE_KIND;
1506   else if (input == "struct")
1507     return type_suppression::STRUCT_TYPE_KIND;
1508   else if (input == "union")
1509     return type_suppression::UNION_TYPE_KIND;
1510   else if (input == "enum")
1511     return type_suppression::ENUM_TYPE_KIND;
1512   else if (input == "array")
1513     return type_suppression::ARRAY_TYPE_KIND;
1514   else if (input == "typedef")
1515     return type_suppression::TYPEDEF_TYPE_KIND;
1516   else if (input == "builtin")
1517     return type_suppression::BUILTIN_TYPE_KIND;
1518   else
1519     return type_suppression::UNKNOWN_TYPE_KIND;
1520 }
1521 
1522 /// Parse the value of the "accessed_through" property in the
1523 /// "suppress_type" section.
1524 ///
1525 /// @param input the input string representing the value of the
1526 /// "accessed_through" property.
1527 ///
1528 /// @return the @ref type_suppression::reach_kind enumerator parsed.
1529 static type_suppression::reach_kind
read_suppression_reach_kind(const string & input)1530 read_suppression_reach_kind(const string& input)
1531 {
1532   if (input == "direct")
1533     return type_suppression::DIRECT_REACH_KIND;
1534   else if (input == "pointer")
1535     return type_suppression::POINTER_REACH_KIND;
1536   else if (input == "reference")
1537     return type_suppression::REFERENCE_REACH_KIND;
1538   else if (input == "reference-or-pointer")
1539     return type_suppression::REFERENCE_OR_POINTER_REACH_KIND;
1540   else
1541     return type_suppression::DIRECT_REACH_KIND;
1542 }
1543 
1544 /// Read a type suppression from an instance of ini::config::section
1545 /// and build a @ref type_suppression as a result.
1546 ///
1547 /// @param section the section of the ini config to read.
1548 ///
1549 /// @return the resulting @ref type_suppression upon successful
1550 /// parsing, or nil.
1551 static type_suppression_sptr
read_type_suppression(const ini::config::section & section)1552 read_type_suppression(const ini::config::section& section)
1553 {
1554   type_suppression_sptr result;
1555 
1556   if (section.get_name() != "suppress_type")
1557     return result;
1558 
1559   static const char *const sufficient_props[] = {
1560     "file_name_regexp",
1561     "file_name_not_regexp",
1562     "soname_regexp",
1563     "soname_not_regexp",
1564     "name",
1565     "name_regexp",
1566     "name_not_regexp",
1567     "type_kind",
1568     "source_location_not_in",
1569     "source_location_not_regexp",
1570   };
1571   if (!check_sufficient_props(sufficient_props,
1572 			      sizeof(sufficient_props)/sizeof(char*),
1573 			      section))
1574     return result;
1575 
1576   ini::simple_property_sptr drop_artifact =
1577     is_simple_property(section.find_property("drop_artifact"));
1578   if (!drop_artifact)
1579     drop_artifact = is_simple_property(section.find_property("drop"));
1580 
1581   string drop_artifact_str = drop_artifact
1582     ? drop_artifact->get_value()->as_string()
1583     : "";
1584 
1585   ini::simple_property_sptr label =
1586     is_simple_property(section.find_property("label"));
1587   string label_str = label ? label->get_value()->as_string() : "";
1588 
1589   ini::simple_property_sptr file_name_regex_prop =
1590     is_simple_property(section.find_property("file_name_regexp"));
1591   string file_name_regex_str =
1592     file_name_regex_prop ? file_name_regex_prop->get_value()->as_string() : "";
1593 
1594   ini::simple_property_sptr file_name_not_regex_prop =
1595     is_simple_property(section.find_property("file_name_not_regexp"));
1596   string file_name_not_regex_str =
1597     file_name_not_regex_prop
1598     ? file_name_not_regex_prop->get_value()->as_string()
1599     : "";
1600 
1601   ini::simple_property_sptr soname_regex_prop =
1602     is_simple_property(section.find_property("soname_regexp"));
1603   string soname_regex_str =
1604     soname_regex_prop ? soname_regex_prop->get_value()->as_string() : "";
1605 
1606   ini::simple_property_sptr soname_not_regex_prop =
1607     is_simple_property(section.find_property("soname_not_regexp"));
1608   string soname_not_regex_str =
1609     soname_not_regex_prop
1610     ? soname_not_regex_prop->get_value()->as_string()
1611     : "";
1612 
1613   ini::simple_property_sptr name_regex_prop =
1614     is_simple_property(section.find_property("name_regexp"));
1615   string name_regex_str = name_regex_prop
1616     ? name_regex_prop->get_value()->as_string()
1617     : "";
1618 
1619   ini::simple_property_sptr name_not_regex_prop =
1620     is_simple_property(section.find_property("name_not_regexp"));
1621   string name_not_regex_str = name_not_regex_prop
1622     ? name_not_regex_prop->get_value()->as_string()
1623     : "";
1624 
1625   ini::simple_property_sptr name_prop =
1626     is_simple_property(section.find_property("name"));
1627   string name_str = name_prop
1628     ? name_prop->get_value()->as_string()
1629     : "";
1630 
1631   ini::property_sptr srcloc_not_in_prop =
1632     section.find_property("source_location_not_in");
1633   unordered_set<string> srcloc_not_in;
1634   if (srcloc_not_in_prop)
1635     {
1636       if (ini::simple_property_sptr p = is_simple_property(srcloc_not_in_prop))
1637 	srcloc_not_in.insert(p->get_value()->as_string());
1638       else
1639 	{
1640 	  ini::list_property_sptr list_property =
1641 	    is_list_property(srcloc_not_in_prop);
1642 	  if (list_property)
1643 	    {
1644 	      vector<string>::const_iterator i;
1645 	      for (i = list_property->get_value()->get_content().begin();
1646 		   i != list_property->get_value()->get_content().end();
1647 		   ++i)
1648 		srcloc_not_in.insert(*i);
1649 	    }
1650 	}
1651     }
1652 
1653   ini::simple_property_sptr srcloc_not_regexp_prop =
1654     is_simple_property(section.find_property("source_location_not_regexp"));
1655   string srcloc_not_regexp_str;
1656   if (srcloc_not_regexp_prop)
1657     srcloc_not_regexp_str = srcloc_not_regexp_prop->get_value()->as_string();
1658 
1659   bool consider_type_kind = false;
1660   type_suppression::type_kind type_kind = type_suppression::UNKNOWN_TYPE_KIND;
1661   if (ini::simple_property_sptr type_kind_prop =
1662       is_simple_property(section.find_property("type_kind")))
1663     {
1664       consider_type_kind = true;
1665       type_kind =
1666 	read_type_kind_string(type_kind_prop->get_value()->as_string());
1667     }
1668 
1669   bool consider_reach_kind = false;
1670   type_suppression::reach_kind reach_kind = type_suppression::DIRECT_REACH_KIND;
1671   if (ini::simple_property_sptr reach_kind_prop =
1672       is_simple_property(section.find_property("accessed_through")))
1673     {
1674       consider_reach_kind = true;
1675       reach_kind =
1676 	read_suppression_reach_kind(reach_kind_prop->get_value()->as_string());
1677     }
1678 
1679   // Support has_data_member_inserted_at
1680   vector<type_suppression::insertion_range_sptr> insert_ranges;
1681   bool consider_data_member_insertion = false;
1682   if (ini::simple_property_sptr prop =
1683       is_simple_property(section.find_property("has_data_member_inserted_at")))
1684     {
1685       // So this property has the form:
1686       //   has_data_member_inserted_at = <one-string-property-value>
1687       string ins_point = prop->get_value()->as_string();
1688       type_suppression::insertion_range::boundary_sptr begin, end;
1689       if (ins_point == "end")
1690 	begin = type_suppression::insertion_range::create_integer_boundary(-1);
1691       else if (isdigit(ins_point[0]))
1692 	begin = type_suppression::insertion_range::create_integer_boundary
1693 	  (atoi(ins_point.c_str()));
1694       else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1695 	       type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(ins_point)))
1696 	begin = expr;
1697       else
1698 	return result;
1699 
1700       end = type_suppression::insertion_range::create_integer_boundary(-1);
1701       type_suppression::insertion_range_sptr insert_range
1702 	(new type_suppression::insertion_range(begin, end));
1703 	  insert_ranges.push_back(insert_range);
1704 	  consider_data_member_insertion = true;
1705     }
1706 
1707   // Support has_data_member_inserted_between
1708   if (ini::tuple_property_sptr prop =
1709       is_tuple_property(section.find_property
1710 			("has_data_member_inserted_between")))
1711     {
1712       // ensures that this has the form:
1713       //  has_data_member_inserted_between = {0 , end};
1714       // and not (for instance):
1715       //  has_data_member_inserted_between = {{0 , end}, {1, foo}}
1716       //
1717       //  This means that the tuple_property_value contains just one
1718       //  value, which is a list_property that itself contains 2
1719       //  values.
1720       type_suppression::insertion_range::boundary_sptr begin, end;
1721       ini::tuple_property_value_sptr v = prop->get_value();
1722       if (v
1723 	  && v->get_value_items().size() == 1
1724 	  && is_list_property_value(v->get_value_items()[0])
1725 	  && is_list_property_value(v->get_value_items()[0])->get_content().size() == 2)
1726 	{
1727 	  ini::list_property_value_sptr val =
1728 	    is_list_property_value(v->get_value_items()[0]);
1729 	  ABG_ASSERT(val);
1730 	  string str = val->get_content()[0];
1731 	  if (str == "end")
1732 	    begin =
1733 	      type_suppression::insertion_range::create_integer_boundary(-1);
1734 	  else if (isdigit(str[0]))
1735 	    begin = type_suppression::insertion_range::create_integer_boundary
1736 	      (atoi(str.c_str()));
1737 	  else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1738 		   type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(str)))
1739 	    begin = expr;
1740 	  else
1741 	    return result;
1742 
1743 	  str = val->get_content()[1];
1744 	  if (str == "end")
1745 	    end =
1746 	      type_suppression::insertion_range::create_integer_boundary(-1);
1747 	  else if (isdigit(str[0]))
1748 	    end = type_suppression::insertion_range::create_integer_boundary
1749 	      (atoi(str.c_str()));
1750 	  else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1751 		   type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(str)))
1752 	    end = expr;
1753 	  else
1754 	    return result;
1755 
1756 	  type_suppression::insertion_range_sptr insert_range
1757 	    (new type_suppression::insertion_range(begin, end));
1758 	  insert_ranges.push_back(insert_range);
1759 	  consider_data_member_insertion = true;
1760 	}
1761       else
1762 	// the 'has_data_member_inserted_between' property has a wrong
1763 	// value type, so let's discard the endire [suppress_type]
1764 	// section.
1765 	return result;
1766     }
1767 
1768   // Support has_data_members_inserted_between
1769   // The syntax looks like:
1770   //
1771   //    has_data_members_inserted_between = {{8, 24}, {32, 64}, {128, end}}
1772   //
1773   // So we expect a tuple property, with potentially several pairs (as
1774   // part of the value); each pair designating a range.  Note that
1775   // each pair (range) is a list property value.
1776   if (ini::tuple_property_sptr prop =
1777       is_tuple_property(section.find_property
1778 			("has_data_members_inserted_between")))
1779     {
1780       bool is_well_formed = true;
1781       for (vector<ini::property_value_sptr>::const_iterator i =
1782 	     prop->get_value()->get_value_items().begin();
1783 	   is_well_formed && i != prop->get_value()->get_value_items().end();
1784 	   ++i)
1785 	{
1786 	  ini::tuple_property_value_sptr tuple_value =
1787 	    is_tuple_property_value(*i);
1788 	  if (!tuple_value
1789 	      || tuple_value->get_value_items().size() != 1
1790 	      || !is_list_property_value(tuple_value->get_value_items()[0]))
1791 	    {
1792 	      is_well_formed = false;
1793 	      break;
1794 	    }
1795 	  ini::list_property_value_sptr list_value =
1796 	    is_list_property_value(tuple_value->get_value_items()[0]);
1797 	  if (list_value->get_content().size() != 2)
1798 	    {
1799 	      is_well_formed = false;
1800 	      break;
1801 	    }
1802 
1803 	  type_suppression::insertion_range::boundary_sptr begin, end;
1804 	  string str = list_value->get_content()[0];
1805 	  if (str == "end")
1806 	    begin =
1807 	      type_suppression::insertion_range::create_integer_boundary(-1);
1808 	  else if (isdigit(str[0]))
1809 	    begin =
1810 	      type_suppression::insertion_range::create_integer_boundary
1811 	      (atoi(str.c_str()));
1812 	  else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1813 		   type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(str)))
1814 	    begin = expr;
1815 	  else
1816 	    return result;
1817 
1818 	  str = list_value->get_content()[1];
1819 	  if (str == "end")
1820 	    end =
1821 	      type_suppression::insertion_range::create_integer_boundary(-1);
1822 	  else if (isdigit(str[0]))
1823 	    end = type_suppression::insertion_range::create_integer_boundary
1824 	      (atoi(str.c_str()));
1825 	  else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1826 		   type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(str)))
1827 	    end = expr;
1828 	  else
1829 	    return result;
1830 
1831 	  type_suppression::insertion_range_sptr insert_range
1832 	    (new type_suppression::insertion_range(begin, end));
1833 	  insert_ranges.push_back(insert_range);
1834 	  consider_data_member_insertion = true;
1835 	}
1836       if (!is_well_formed)
1837 	return result;
1838     }
1839 
1840   /// Support 'changed_enumerators = foo, bar, baz'
1841   ///
1842   /// Note that this constraint is valid only if we have:
1843   ///   'type_kind = enum'.
1844   ///
1845   /// If the current type is an enum and if it carries changed
1846   /// enumerators listed in the changed_enumerators property value
1847   /// then it should be suppressed.
1848 
1849   ini::property_sptr changed_enumerators_prop =
1850     section.find_property("changed_enumerators");
1851 
1852   vector<string> changed_enumerator_names;
1853   if (changed_enumerators_prop)
1854     {
1855       if (ini::list_property_sptr p =
1856 	  is_list_property(changed_enumerators_prop))
1857 	changed_enumerator_names =
1858 	  p->get_value()->get_content();
1859       else if (ini::simple_property_sptr p =
1860 	       is_simple_property(changed_enumerators_prop))
1861 	changed_enumerator_names.push_back(p->get_value()->as_string());
1862     }
1863 
1864   result.reset(new type_suppression(label_str, name_regex_str, name_str));
1865 
1866   if (consider_type_kind)
1867     {
1868       result->set_consider_type_kind(true);
1869       result->set_type_kind(type_kind);
1870     }
1871 
1872   if (consider_reach_kind)
1873     {
1874       result->set_consider_reach_kind(true);
1875       result->set_reach_kind(reach_kind);
1876     }
1877 
1878   if (consider_data_member_insertion)
1879     result->set_data_member_insertion_ranges(insert_ranges);
1880 
1881   if (!name_not_regex_str.empty())
1882     result->set_type_name_not_regex_str(name_not_regex_str);
1883 
1884   if (!file_name_regex_str.empty())
1885     result->set_file_name_regex_str(file_name_regex_str);
1886 
1887   if (!file_name_not_regex_str.empty())
1888     result->set_file_name_not_regex_str(file_name_not_regex_str);
1889 
1890   if (!soname_regex_str.empty())
1891     result->set_soname_regex_str(soname_regex_str);
1892 
1893   if (!soname_not_regex_str.empty())
1894     result->set_soname_not_regex_str(soname_not_regex_str);
1895 
1896   if (!srcloc_not_in.empty())
1897     result->set_source_locations_to_keep(srcloc_not_in);
1898 
1899   if (!srcloc_not_regexp_str.empty())
1900     result->set_source_location_to_keep_regex_str(srcloc_not_regexp_str);
1901 
1902   if ((drop_artifact_str == "yes" || drop_artifact_str == "true")
1903       && ((!name_regex_str.empty()
1904 	   || !name_str.empty()
1905 	   || !srcloc_not_regexp_str.empty()
1906 	   || !srcloc_not_in.empty())))
1907     result->set_drops_artifact_from_ir(true);
1908 
1909   if (result->get_type_kind() == type_suppression::ENUM_TYPE_KIND
1910       && !changed_enumerator_names.empty())
1911     result->set_changed_enumerator_names(changed_enumerator_names);
1912 
1913   return result;
1914 }
1915 
1916 // <function_suppression stuff>
1917 
1918 /// Constructor for the @ref the function_suppression::parameter_spec
1919 /// type.
1920 ///
1921 /// @param i the index of the parameter designated by this specification.
1922 ///
1923 /// @param tn the type name of the parameter designated by this specification.
1924 ///
1925 /// @param tn_regex a regular expression that defines a set of type
1926 /// names for the parameter designated by this specification.  Note
1927 /// that at evaluation time, this regular expression is taken in
1928 /// account only if the parameter @p tn is empty.
parameter_spec(size_t i,const string & tn,const string & tn_regex)1929 function_suppression::parameter_spec::parameter_spec(size_t i,
1930 						     const string& tn,
1931 						     const string& tn_regex)
1932   : priv_(new priv(i, tn, tn_regex))
1933 {}
1934 
1935 /// Getter for the index of the parameter designated by this
1936 /// specification.
1937 ///
1938 /// @return the index of the parameter designated by this
1939 /// specification.
1940 size_t
get_index() const1941 function_suppression::parameter_spec::get_index() const
1942 {return priv_->index_;}
1943 
1944 /// Setter for the index of the parameter designated by this
1945 /// specification.
1946 ///
1947 /// @param i the new index to set.
1948 void
set_index(size_t i)1949 function_suppression::parameter_spec::set_index(size_t i)
1950 {priv_->index_ = i;}
1951 
1952 /// Getter for the type name of the parameter designated by this specification.
1953 ///
1954 /// @return the type name of the parameter.
1955 const string&
get_parameter_type_name() const1956 function_suppression::parameter_spec::get_parameter_type_name() const
1957 {return priv_->type_name_;}
1958 
1959 /// Setter for the type name of the parameter designated by this
1960 /// specification.
1961 ///
1962 /// @param tn new parameter type name to set.
1963 void
set_parameter_type_name(const string & tn)1964 function_suppression::parameter_spec::set_parameter_type_name(const string& tn)
1965 {priv_->type_name_ = tn;}
1966 
1967 /// Getter for the regular expression that defines a set of type names
1968 /// for the parameter designated by this specification.
1969 ///
1970 /// Note that at evaluation time, this regular expression is taken in
1971 /// account only if the name of the parameter as returned by
1972 /// function_suppression::parameter_spec::get_parameter_type_name() is
1973 /// empty.
1974 ///
1975 /// @return the regular expression or the parameter type name.
1976 const string&
get_parameter_type_name_regex_str() const1977 function_suppression::parameter_spec::get_parameter_type_name_regex_str() const
1978 {return priv_->type_name_regex_str_;}
1979 
1980 /// Setter for the regular expression that defines a set of type names
1981 /// for the parameter designated by this specification.
1982 ///
1983 /// Note that at evaluation time, this regular expression is taken in
1984 /// account only if the name of the parameter as returned by
1985 /// function_suppression::parameter_spec::get_parameter_type_name() is
1986 /// empty.
1987 ///
1988 /// @param type_name_regex_str the new type name regular expression to
1989 /// set.
1990 void
set_parameter_type_name_regex_str(const string & type_name_regex_str)1991 function_suppression::parameter_spec::set_parameter_type_name_regex_str
1992 (const string& type_name_regex_str)
1993 {priv_->type_name_regex_str_ = type_name_regex_str;}
1994 
1995 /// Default constructor for the @ref function_suppression type.
1996 ///
1997 /// It defines no suppression for now.  Suppressions have to be
1998 /// specified by using the various accessors of the @ref
1999 /// function_suppression type.
function_suppression()2000 function_suppression::function_suppression()
2001   :  suppression_base(/*label=*/""), priv_(new priv)
2002 {}
2003 
2004 /// Constructor for the @ref function_suppression type.
2005 ///
2006 /// @param label an informative text string that the evalution code
2007 /// might use to designate this function suppression specification in
2008 /// error messages.  This parameter might be empty, in which case it's
2009 /// ignored at evaluation time.
2010 ///
2011 /// @param the name of the function the user wants the current
2012 /// specification to designate.  This parameter might be empty, in
2013 /// which case it's ignored at evaluation time.
2014 ///
2015 /// @param nr if @p name is empty this parameter is a regular
2016 /// expression for a family of names of functions the user wants the
2017 /// current specification to designate.  If @p name is not empty, this
2018 /// parameter is ignored at specification evaluation time.  This
2019 /// parameter might be empty, in which case it's ignored at evaluation
2020 /// time.
2021 ///
2022 /// @param ret_tn the name of the return type of the function the user
2023 /// wants this specification to designate.  This parameter might be
2024 /// empty, in which case it's ignored at evaluation time.
2025 ///
2026 /// @param ret_tr if @p ret_tn is empty, then this is a regular
2027 /// expression for a family of return type names for functions the
2028 /// user wants the current specification to designate.  If @p ret_tn
2029 /// is not empty, then this parameter is ignored at specification
2030 /// evaluation time.  This parameter might be empty, in which case
2031 /// it's ignored at evaluation time.
2032 ///
2033 /// @param ps a vector of parameter specifications to specify
2034 /// properties of the parameters of the functions the user wants this
2035 /// specification to designate.  This parameter might be empty, in
2036 /// which case it's ignored at evaluation time.
2037 ///
2038 /// @param sym_n the name of symbol of the function the user wants
2039 /// this specification to designate.  This parameter might be empty,
2040 /// in which case it's ignored at evaluation time.
2041 ///
2042 /// @param sym_nr if the parameter @p sym_n is empty, then this
2043 /// parameter is a regular expression for a family of names of symbols
2044 /// of functions the user wants this specification to designate.  If
2045 /// the parameter @p sym_n is not empty, then this parameter is
2046 /// ignored at specification evaluation time.  This parameter might be
2047 /// empty, in which case it's ignored at evaluation time.
2048 ///
2049 /// @param sym_v the name of the version of the symbol of the function
2050 /// the user wants this specification to designate.  This parameter
2051 /// might be empty, in which case it's ignored at evaluation time.
2052 ///
2053 /// @param sym_vr if the parameter @p sym_v is empty, then this
2054 /// parameter is a regular expression for a family of versions of
2055 /// symbols of functions the user wants the current specification to
2056 /// designate.  If the parameter @p sym_v is non empty, then this
2057 /// parameter is ignored.  This parameter might be empty, in which
2058 /// 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)2059 function_suppression::function_suppression(const string&		label,
2060 					   const string&		name,
2061 					   const string&		nr,
2062 					   const string&		ret_tn,
2063 					   const string&		ret_tr,
2064 					   parameter_specs_type&	ps,
2065 					   const string&		sym_n,
2066 					   const string&		sym_nr,
2067 					   const string&		sym_v,
2068 					   const string&		sym_vr)
2069   : suppression_base(label),
2070     priv_(new priv(name, nr, ret_tn, ret_tr, ps,
2071 		   sym_n, sym_nr, sym_v, sym_vr))
2072 {}
2073 
~function_suppression()2074 function_suppression::~function_suppression()
2075 {}
2076 
2077 /// Parses a string containing the content of the "change-kind"
2078 /// property and returns the an instance of @ref
2079 /// function_suppression::change_kind as a result.
2080 ///
2081 /// @param s the string to parse.
2082 ///
2083 /// @return the resulting @ref function_suppression::change_kind.
2084 function_suppression::change_kind
parse_change_kind(const string & s)2085 function_suppression::parse_change_kind(const string& s)
2086 {
2087   if (s == "function-subtype-change")
2088     return FUNCTION_SUBTYPE_CHANGE_KIND;
2089   else if (s == "added-function")
2090     return ADDED_FUNCTION_CHANGE_KIND;
2091   else if (s == "deleted-function")
2092     return DELETED_FUNCTION_CHANGE_KIND;
2093   else if (s == "all")
2094     return ALL_CHANGE_KIND;
2095   else
2096     return UNDEFINED_CHANGE_KIND;
2097 }
2098 
2099 /// Getter of the "change-kind" property.
2100 ///
2101 /// @param returnthe "change-kind" property.
2102 function_suppression::change_kind
get_change_kind() const2103 function_suppression::get_change_kind() const
2104 {return priv_->change_kind_;}
2105 
2106 /// Setter of the "change-kind" property.
2107 ///
2108 /// @param k the new value of the change_kind property.
2109 void
set_change_kind(change_kind k)2110 function_suppression::set_change_kind(change_kind k)
2111 {priv_->change_kind_ = k;}
2112 
2113 /// Getter for the name of the function the user wants the current
2114 /// specification to designate.  This might be empty, in which case
2115 /// it's ignored at evaluation time.
2116 ///
2117 /// @return the name of the function.
2118 const string&
get_name() const2119 function_suppression::get_name() const
2120 {return priv_->name_;}
2121 
2122 /// Setter for the name of the function the user wants the current
2123 /// specification to designate.  This might be empty, in which case
2124 /// it's ignored at evaluation time.
2125 ///
2126 /// @param n the new function name to set.
2127 void
set_name(const string & n)2128 function_suppression::set_name(const string& n)
2129 {priv_->name_ = n;}
2130 
2131 /// Getter for a regular expression for a family of names of functions
2132 /// the user wants the current specification to designate.
2133 ///
2134 /// @return the regular expression for the possible names of the
2135 /// function(s).
2136 const string&
get_name_regex_str() const2137 function_suppression::get_name_regex_str() const
2138 {return priv_->name_regex_str_;}
2139 
2140 /// Setter for a regular expression for a family of names of functions
2141 /// the user wants the current specification to designate.
2142 ///
2143 /// @param r the new the regular expression for the possible names of
2144 /// the function(s).
2145 void
set_name_regex_str(const string & r)2146 function_suppression::set_name_regex_str(const string& r)
2147 {priv_->name_regex_str_ = r;}
2148 
2149 /// Getter for a regular expression of a family of names of functions
2150 /// the user wants the current specification to designate the negation
2151 /// of.
2152 ///
2153 /// @return the regular expression for the possible names of the
2154 /// function(s).
2155 const string&
get_name_not_regex_str() const2156 function_suppression::get_name_not_regex_str() const
2157 {return priv_->name_not_regex_str_;}
2158 
2159 /// Setter for a regular expression for a family of names of functions
2160 /// the user wants the current specification to designate the negation
2161 /// of.
2162 ///
2163 /// @param r the new the regular expression for the possible names of
2164 /// the function(s).
2165 void
set_name_not_regex_str(const string & r)2166 function_suppression::set_name_not_regex_str(const string& r)
2167 {priv_->name_not_regex_str_ = r;}
2168 
2169 /// Getter for the name of the return type of the function the user
2170 /// wants this specification to designate.  This property might be
2171 /// empty, in which case it's ignored at evaluation time.
2172 ///
2173 /// @return the name of the return type of the function.
2174 const string&
get_return_type_name() const2175 function_suppression::get_return_type_name() const
2176 {return priv_->return_type_name_;}
2177 
2178 /// Setter for the name of the return type of the function the user
2179 /// wants this specification to designate.  This property might be
2180 /// empty, in which case it's ignored at evaluation time.
2181 ///
2182 /// @param tr the new name of the return type of the function to set.
2183 void
set_return_type_name(const string & tr)2184 function_suppression::set_return_type_name(const string& tr)
2185 {priv_->return_type_name_ = tr;}
2186 
2187 /// Getter for a regular expression for a family of return type names
2188 /// for functions the user wants the current specification to
2189 /// designate.
2190 ///
2191 /// If the name of the return type of the function as returned by
2192 /// function_suppression::get_return_type_name() is not empty, then
2193 /// this property is ignored at specification evaluation time.  This
2194 /// property might be empty, in which case it's ignored at evaluation
2195 /// time.
2196 ///
2197 /// @return the regular expression for the possible names of the
2198 /// return types of the function(s).
2199 const string&
get_return_type_regex_str() const2200 function_suppression::get_return_type_regex_str() const
2201 {return priv_->return_type_regex_str_;}
2202 
2203 /// Setter for a regular expression for a family of return type names
2204 /// for functions the user wants the current specification to
2205 /// designate.
2206 ///
2207 /// If the name of the return type of the function as returned by
2208 /// function_suppression::get_return_type_name() is not empty, then
2209 /// this property is ignored at specification evaluation time.  This
2210 /// property might be empty, in which case it's ignored at evaluation
2211 /// time.
2212 ///
2213 /// @param r the new regular expression for the possible names of the
2214 /// return types of the function(s) to set.
2215 void
set_return_type_regex_str(const string & r)2216 function_suppression::set_return_type_regex_str(const string& r)
2217 {priv_->return_type_regex_str_ = r;}
2218 
2219 /// Getter for a vector of parameter specifications to specify
2220 /// properties of the parameters of the functions the user wants this
2221 /// specification to designate.
2222 ///
2223 /// This property might be empty, in which case it's ignored at
2224 /// evaluation time.
2225 ///
2226 /// @return the specifications of the parameters of the function(s).
2227 const function_suppression::parameter_specs_type&
get_parameter_specs() const2228 function_suppression::get_parameter_specs() const
2229 {return priv_->parm_specs_;}
2230 
2231 /// Setter for a vector of parameter specifications to specify
2232 /// properties of the parameters of the functions the user wants this
2233 /// specification to designate.
2234 ///
2235 /// This property might be empty, in which case it's ignored at
2236 /// evaluation time.
2237 ///
2238 /// @param p the new specifications of the parameters of the
2239 /// function(s) to set.
2240 void
set_parameter_specs(parameter_specs_type & p)2241 function_suppression::set_parameter_specs(parameter_specs_type& p)
2242 {priv_->parm_specs_ = p;}
2243 
2244 /// Append a specification of a parameter of the function specification.
2245 ///
2246 /// @param p the parameter specification to add.
2247 void
append_parameter_specs(const parameter_spec_sptr p)2248 function_suppression::append_parameter_specs(const parameter_spec_sptr p)
2249 {priv_->parm_specs_.push_back(p);}
2250 
2251 /// Getter for the name of symbol of the function the user wants this
2252 /// specification to designate.
2253 ///
2254 /// This property might be empty, in which case it's ignored at
2255 /// evaluation time.
2256 ///
2257 /// @return name of the symbol of the function.
2258 const string&
get_symbol_name() const2259 function_suppression::get_symbol_name() const
2260 {return priv_->symbol_name_;}
2261 
2262 /// Setter for the name of symbol of the function the user wants this
2263 /// specification to designate.
2264 ///
2265 /// This property might be empty, in which case it's ignored at
2266 /// evaluation time.
2267 ///
2268 /// @return name of the symbol of the function.
2269 void
set_symbol_name(const string & n)2270 function_suppression::set_symbol_name(const string& n)
2271 {priv_->symbol_name_ = n;}
2272 
2273 /// Getter for a regular expression for a family of names of symbols
2274 /// of functions the user wants this specification to designate.
2275 ///
2276 /// If the symbol name as returned by
2277 /// function_suppression::get_symbol_name() is not empty, then this
2278 /// property is ignored at specification evaluation time.
2279 ///
2280 /// This property might be empty, in which case it's ignored at
2281 /// evaluation time.
2282 ///
2283 /// @return the regular expression for a family of names of symbols of
2284 /// functions to designate.
2285 const string&
get_symbol_name_regex_str() const2286 function_suppression::get_symbol_name_regex_str() const
2287 {return priv_->symbol_name_regex_str_;}
2288 
2289 /// Setter for a regular expression for a family of names of symbols
2290 /// of functions the user wants this specification to designate.
2291 ///
2292 /// If the symbol name as returned by
2293 /// function_suppression::get_symbol_name() is not empty, then this
2294 /// property is ignored at specification evaluation time.
2295 ///
2296 /// This property might be empty, in which case it's ignored at
2297 /// evaluation time.
2298 ///
2299 /// @param r the new regular expression for a family of names of
2300 /// symbols of functions to set.
2301 void
set_symbol_name_regex_str(const string & r)2302 function_suppression::set_symbol_name_regex_str(const string& r)
2303 {priv_->symbol_name_regex_str_ = r;}
2304 
2305 /// Getter for a regular expression for a family of names of symbols
2306 /// of functions the user wants this specification to designate.
2307 ///
2308 /// If a symbol name is matched by this regular expression, then the
2309 /// suppression specification will *NOT* suppress the symbol.
2310 ///
2311 /// If the symbol name as returned by
2312 /// function_suppression::get_symbol_name() is not empty, then this
2313 /// property is ignored at specification evaluation time.
2314 ///
2315 /// This property might be empty, in which case it's ignored at
2316 /// evaluation time.
2317 ///
2318 /// @return the regular expression string for a family of names of
2319 /// symbols that is to be *NOT* suppressed by this suppression specification.
2320 const string&
get_symbol_name_not_regex_str() const2321 function_suppression::get_symbol_name_not_regex_str() const
2322 {return priv_->symbol_name_not_regex_str_;}
2323 
2324 /// Setter for a regular expression for a family of names of symbols
2325 /// of functions the user wants this specification to designate.
2326 ///
2327 /// If a symbol name is matched by this regular expression, then the
2328 /// suppression specification will *NOT* suppress the symbol.
2329 ///
2330 /// If the symbol name as returned by
2331 /// function_suppression::get_symbol_name() is not empty, then this
2332 /// property is ignored at specification evaluation time.
2333 ///
2334 /// This property might be empty, in which case it's ignored at
2335 /// evaluation time.
2336 ///
2337 /// @param the new regular expression string for a family of names of
2338 /// symbols that is to be *NOT* suppressed by this suppression
2339 /// specification.
2340 void
set_symbol_name_not_regex_str(const string & r)2341 function_suppression::set_symbol_name_not_regex_str(const string& r)
2342 {priv_->symbol_name_not_regex_str_ = r;}
2343 
2344 /// Getter for the name of the version of the symbol of the function
2345 /// the user wants this specification to designate.
2346 ///
2347 /// This property might be empty, in which case it's ignored at
2348 /// evaluation time.
2349 ///
2350 /// @return the symbol version of the function.
2351 const string&
get_symbol_version() const2352 function_suppression::get_symbol_version() const
2353 {return priv_->symbol_version_;}
2354 
2355 /// Setter for the name of the version of the symbol of the function
2356 /// the user wants this specification to designate.
2357 ///
2358 /// This property might be empty, in which case it's ignored at
2359 /// evaluation time.
2360 ///
2361 /// @param v the new symbol version of the function.
2362 void
set_symbol_version(const string & v)2363 function_suppression::set_symbol_version(const string& v)
2364 {priv_->symbol_version_ = v;}
2365 
2366 /// Getter for a regular expression for a family of versions of
2367 /// symbols of functions the user wants the current specification to
2368 /// designate.
2369 ///
2370 /// If the symbol version as returned by
2371 /// function_suppression::get_symbol_version() is non empty, then this
2372 /// property is ignored.  This property might be empty, in which case
2373 /// it's ignored at evaluation time.
2374 ///
2375 /// @return the regular expression for the versions of symbols of
2376 /// functions to designate.
2377 const string&
get_symbol_version_regex_str() const2378 function_suppression::get_symbol_version_regex_str() const
2379 {return priv_->symbol_version_regex_str_;}
2380 
2381 /// Setter for a regular expression for a family of versions of
2382 /// symbols of functions the user wants the current specification to
2383 /// designate.
2384 ///
2385 /// If the symbol version as returned by
2386 /// function_suppression::get_symbol_version() is non empty, then this
2387 /// property is ignored.  This property might be empty, in which case
2388 /// it's ignored at evaluation time.
2389 ///
2390 /// @param the new regular expression for the versions of symbols of
2391 /// functions to designate.
2392 void
set_symbol_version_regex_str(const string & r)2393 function_suppression::set_symbol_version_regex_str(const string& r)
2394 {priv_->symbol_version_regex_str_ = r;}
2395 
2396 /// Getter for the "allow_other_aliases" property of the function
2397 /// suppression specification.
2398 ///
2399 /// @return the value of the "allow_other_aliases" property.
2400 bool
get_allow_other_aliases() const2401 function_suppression::get_allow_other_aliases() const
2402 {return priv_->allow_other_aliases_;}
2403 
2404 /// Setter for the "allow_other_aliases" property of the function
2405 /// suppression specification.
2406 ///
2407 /// @param f the new value of the property.
2408 void
set_allow_other_aliases(bool f)2409 function_suppression::set_allow_other_aliases(bool f)
2410 {priv_->allow_other_aliases_ = f;}
2411 
2412 /// Evaluate this suppression specification on a given diff node and
2413 /// say if the diff node should be suppressed or not.
2414 ///
2415 /// @param diff the diff node to evaluate this suppression
2416 /// specification against.
2417 ///
2418 /// @return true if @p diff should be suppressed.
2419 bool
suppresses_diff(const diff * diff) const2420 function_suppression::suppresses_diff(const diff* diff) const
2421 {
2422   const function_decl_diff* d = is_function_decl_diff(diff);
2423   if (!d)
2424     return false;
2425 
2426   function_decl_sptr ff = is_function_decl(d->first_function_decl()),
2427     sf = is_function_decl(d->second_function_decl());
2428   ABG_ASSERT(ff && sf);
2429 
2430   return (suppresses_function(ff,
2431 			      FUNCTION_SUBTYPE_CHANGE_KIND,
2432 			      diff->context())
2433 	  || suppresses_function(sf,
2434 				 FUNCTION_SUBTYPE_CHANGE_KIND,
2435 				 diff->context()));
2436 }
2437 
2438 /// Evaluate the current function suppression specification on a given
2439 /// @ref function_decl and say if a report about a change involving this
2440 /// @ref function_decl should be suppressed or not.
2441 ///
2442 /// @param fn the @ref function_decl to evaluate this suppression
2443 /// specification against.
2444 ///
2445 /// @param k the kind of function change @p fn is supposed to have.
2446 ///
2447 /// @param ctxt the context of the current diff.
2448 ///
2449 /// @return true iff a report about a change involving the function @p
2450 /// fn should be suppressed.
2451 bool
suppresses_function(const function_decl * fn,change_kind k,const diff_context_sptr ctxt) const2452 function_suppression::suppresses_function(const function_decl* fn,
2453 					  change_kind k,
2454 					  const diff_context_sptr ctxt) const
2455 {
2456   if (!(get_change_kind() & k))
2457     return false;
2458 
2459   // Check if the name and soname of the binaries match the current
2460   // suppr spec
2461   if (ctxt)
2462     {
2463       // Check if the name of the binaries match the current suppr spec
2464       if (!names_of_binaries_match(*this, *ctxt))
2465 	if (has_file_name_related_property())
2466 	  return false;
2467 
2468       // Check if the soname of the binaries match the current suppr spec
2469       if (!sonames_of_binaries_match(*this, *ctxt))
2470 	if (has_soname_related_property())
2471 	  return false;
2472     }
2473 
2474   string fname = fn->get_qualified_name();
2475 
2476   // Check if the "name" property matches.
2477   if (!get_name().empty())
2478     {
2479       if (get_name() != fn->get_qualified_name())
2480 	return false;
2481 
2482       if (get_allow_other_aliases()
2483 	  && fn->get_symbol()
2484 	  && fn->get_symbol()->get_alias_from_name(fname))
2485 	{
2486 	  // So we are in a case of a languages in which the symbol
2487 	  // name is the same as the function name and we want to
2488 	  // allow the removal of change reports on an aliased
2489 	  // function only if the suppression condition matches the
2490 	  // names of all aliases.
2491 	  string symbol_name;
2492 	  elf_symbol_sptr sym = fn->get_symbol();
2493 	  ABG_ASSERT(sym);
2494 	  symbol_name = sym->get_name();
2495 	  if (sym->has_aliases() && sym->get_alias_from_name(fname))
2496 	    {
2497 	      for (elf_symbol_sptr a = sym->get_next_alias();
2498 		   a && !a->is_main_symbol();
2499 		   a = a->get_next_alias())
2500 		if (a->get_name() != symbol_name)
2501 		  // There is an alias which name is different from
2502 		  // the function (symbol) name given in the
2503 		  // suppression condition.
2504 		  return false;
2505 	    }
2506 	}
2507     }
2508 
2509   // check if the "name_regexp" property matches.
2510   const regex_t_sptr name_regex = priv_->get_name_regex();
2511   if (name_regex)
2512     {
2513       if (!regex::match(name_regex, fname))
2514 	return false;
2515 
2516       if (get_allow_other_aliases()
2517 	  && fn->get_symbol()
2518 	  && fn->get_symbol()->get_alias_from_name(fname))
2519 	{
2520 	  // So we are in a case of a languages in which the symbol
2521 	  // name is the same as the function name and we want to
2522 	  // allow the removal of change reports on an aliased
2523 	  // function only if the suppression condition matches *all*
2524 	  // the aliases.
2525 	  string symbol_name;
2526 	  elf_symbol_sptr sym = fn->get_symbol();
2527 	  ABG_ASSERT(sym);
2528 	  symbol_name = sym->get_name();
2529 	  if (sym->has_aliases())
2530 	    {
2531 	      for (elf_symbol_sptr a = sym->get_next_alias();
2532 		   a && !a->is_main_symbol();
2533 		   a = a->get_next_alias())
2534 		if (!regex::match(name_regex, a->get_name()))
2535 		  return false;
2536 	    }
2537 	}
2538     }
2539 
2540   // check if the "name_not_regexp" property matches.
2541   const regex_t_sptr name_not_regex = priv_->get_name_not_regex();
2542   if (name_not_regex)
2543     {
2544       if (regex::match(name_not_regex, fname))
2545 	return false;
2546 
2547       if (get_allow_other_aliases()
2548 	  && fn->get_symbol()
2549 	  && fn->get_symbol()->get_alias_from_name(fname))
2550 	{
2551 	  // So we are in a case of a languages in which the symbol
2552 	  // name is the same as the function name and we want to
2553 	  // allow the removal of change reports on an aliased
2554 	  // function only if the suppression condition matches *all*
2555 	  // the aliases.
2556 	  string symbol_name;
2557 	  elf_symbol_sptr sym = fn->get_symbol();
2558 	  ABG_ASSERT(sym);
2559 	  symbol_name = sym->get_name();
2560 	  if (sym->has_aliases())
2561 	    {
2562 	      for (elf_symbol_sptr a = sym->get_next_alias();
2563 		   a && !a->is_main_symbol();
2564 		   a = a->get_next_alias())
2565 		if (regex::match(name_regex, a->get_name()))
2566 		  return false;
2567 	    }
2568 	}
2569     }
2570 
2571   // Check if the "return_type_name" or "return_type_regexp"
2572   // properties matches.
2573 
2574   string fn_return_type_name = fn->get_type()->get_return_type()
2575     ? static_cast<string>
2576     ((get_type_declaration(fn->get_type()->get_return_type())
2577       ->get_qualified_name()))
2578     : "";
2579 
2580   if (!get_return_type_name().empty())
2581     {
2582       if (fn_return_type_name != get_return_type_name())
2583 	return false;
2584     }
2585   else
2586     {
2587       const regex_t_sptr return_type_regex = priv_->get_return_type_regex();
2588       if (return_type_regex
2589 	  && !regex::match(return_type_regex, fn_return_type_name))
2590 	return false;
2591     }
2592 
2593   // Check if the "symbol_name", "symbol_name_regexp", and
2594   // "symbol_name_not_regexp" properties match.
2595   string fn_sym_name, fn_sym_version;
2596   elf_symbol_sptr sym = fn->get_symbol();
2597   if (sym)
2598     {
2599       fn_sym_name = sym->get_name();
2600       fn_sym_version = sym->get_version().str();
2601     }
2602 
2603   if (sym && !get_symbol_name().empty())
2604     {
2605       if (fn_sym_name != get_symbol_name())
2606 	return false;
2607 
2608       if (sym && get_allow_other_aliases())
2609 	{
2610 	  // In this case, we want to allow the suppression of change
2611 	  // reports about an aliased symbol only if the suppression
2612 	  // condition matches the name of all aliases.
2613 	  if (sym->has_aliases())
2614 	    {
2615 	      for (elf_symbol_sptr a = sym->get_next_alias();
2616 		   a && !a->is_main_symbol();
2617 		   a = a->get_next_alias())
2618 		if (a->get_name() != fn_sym_name)
2619 		  return false;
2620 	    }
2621 	}
2622     }
2623   else if (sym)
2624     {
2625       const regex_t_sptr symbol_name_regex = priv_->get_symbol_name_regex();
2626       if (symbol_name_regex && !regex::match(symbol_name_regex, fn_sym_name))
2627 	return false;
2628 
2629       const regex_t_sptr symbol_name_not_regex =
2630 	priv_->get_symbol_name_not_regex();
2631       if (symbol_name_not_regex
2632 	  && regex::match(symbol_name_not_regex, fn_sym_name))
2633 	return false;
2634 
2635       if (get_allow_other_aliases())
2636 	{
2637 	  // In this case, we want to allow the suppression of change
2638 	  // reports about an aliased symbol only if the suppression
2639 	  // condition matches the name of all aliases.
2640 	  if (sym->has_aliases())
2641 	    {
2642 	      for (elf_symbol_sptr a = sym->get_next_alias();
2643 		   a && !a->is_main_symbol();
2644 		   a = a->get_next_alias())
2645 		{
2646 		  if (symbol_name_regex
2647 		      && !regex::match(symbol_name_regex, a->get_name()))
2648 		    return false;
2649 
2650 		  if (symbol_name_not_regex
2651 		      && regex::match(symbol_name_not_regex, a->get_name()))
2652 		    return false;
2653 		}
2654 	    }
2655 	}
2656     }
2657 
2658   // Check if the "symbol_version" and "symbol_version_regexp"
2659   // properties match.
2660   if (sym && !get_symbol_version().empty())
2661     {
2662       if (fn_sym_version != get_symbol_version())
2663 	return false;
2664     }
2665   else if (sym)
2666     {
2667       const regex_t_sptr symbol_version_regex =
2668 	priv_->get_symbol_version_regex();
2669       if (symbol_version_regex
2670 	  && !regex::match(symbol_version_regex, fn_sym_version))
2671 	return false;
2672     }
2673 
2674   // Check the 'parameter' property.
2675   if (!get_parameter_specs().empty())
2676     {
2677       function_type_sptr fn_type = fn->get_type();
2678       type_base_sptr parm_type;
2679 
2680       for (parameter_specs_type::const_iterator p =
2681 	     get_parameter_specs().begin();
2682 	   p != get_parameter_specs().end();
2683 	   ++p)
2684 	{
2685 	  size_t index = (*p)->get_index();
2686 	  function_decl::parameter_sptr fn_parm =
2687 	    fn_type->get_parm_at_index_from_first_non_implicit_parm(index);
2688 	  if (!fn_parm)
2689 	    return false;
2690 
2691 	  string fn_parm_type_qualified_name;
2692 	  if (fn_parm)
2693 	    {
2694 	      parm_type = fn_parm->get_type();
2695 	      fn_parm_type_qualified_name =
2696 		get_type_declaration(parm_type)->get_qualified_name();
2697 	    }
2698 
2699 	  const string& tn = (*p)->get_parameter_type_name();
2700 	  if (!tn.empty())
2701 	    {
2702 	      if (tn != fn_parm_type_qualified_name)
2703 		return false;
2704 	    }
2705 	  else
2706 	    {
2707 	      const regex_t_sptr parm_type_name_regex =
2708 		(*p)->priv_->get_type_name_regex();
2709 	      if (parm_type_name_regex)
2710 		{
2711 		  if (!regex::match(parm_type_name_regex,
2712 				    fn_parm_type_qualified_name))
2713 		    return false;
2714 		}
2715 	    }
2716 	}
2717     }
2718 
2719   return true;
2720 }
2721 
2722 /// Evaluate the current function suppression specification on a given
2723 /// @ref function_decl and say if a report about a change involving this
2724 /// @ref function_decl should be suppressed or not.
2725 ///
2726 /// @param fn the @ref function_decl to evaluate this suppression
2727 /// specification against.
2728 ///
2729 /// @param k the kind of function change @p fn is supposed to have.
2730 ///
2731 /// @param ctxt the context of the current diff.
2732 ///
2733 /// @return true iff a report about a change involving the function @p
2734 /// fn should be suppressed.
2735 bool
suppresses_function(const function_decl_sptr fn,change_kind k,const diff_context_sptr ctxt) const2736 function_suppression::suppresses_function(const function_decl_sptr fn,
2737 					  change_kind k,
2738 					  const diff_context_sptr ctxt) const
2739 {return suppresses_function(fn.get(), k, ctxt);}
2740 
2741 /// Evaluate the current function suppression specification on a given
2742 /// @ref elf_symbol and say if a report about a change involving this
2743 /// @ref elf_symbol should be suppressed or not.
2744 ///
2745 /// @param sym the @ref elf_symbol to evaluate this suppression
2746 /// specification against.
2747 ///
2748 /// @param k the kind of function change @p sym is supposed to have.
2749 ///
2750 /// @param ctxt the context of the current diff.
2751 ///
2752 /// @return true iff a report about a change involving the symbol @p
2753 /// sym should be suppressed.
2754 bool
suppresses_function_symbol(const elf_symbol * sym,change_kind k,const diff_context_sptr ctxt)2755 function_suppression::suppresses_function_symbol(const elf_symbol* sym,
2756 						 change_kind k,
2757 						 const diff_context_sptr ctxt)
2758 {
2759   if (!sym)
2760     return false;
2761 
2762   if (!(get_change_kind() & k))
2763     return false;
2764 
2765   if (!sym->is_function())
2766     return false;
2767 
2768   ABG_ASSERT(k & function_suppression::ADDED_FUNCTION_CHANGE_KIND
2769 	 || k & function_suppression::DELETED_FUNCTION_CHANGE_KIND);
2770 
2771   // Check if the name and soname of the binaries match the current
2772   // suppr spect
2773   if (ctxt)
2774     {
2775       // Check if the name of the binaries match the current
2776       // suppr spect
2777       if (!names_of_binaries_match(*this, *ctxt))
2778 	if (has_file_name_related_property())
2779 	  return false;
2780 
2781       // Check if the soname of the binaries match the current
2782       // suppr spect
2783       if (!sonames_of_binaries_match(*this, *ctxt))
2784 	if (has_soname_related_property())
2785 	  return false;
2786     }
2787 
2788   string sym_name = sym->get_name(), sym_version = sym->get_version().str();
2789   bool no_symbol_name = false, no_symbol_version = false;
2790 
2791   // Consider the symbol name.
2792   if (!get_symbol_name().empty())
2793     {
2794       if (sym_name != get_symbol_name())
2795 	return false;
2796     }
2797   else if (!get_symbol_name_regex_str().empty())
2798     {
2799       const regex_t_sptr symbol_name_regex = priv_->get_symbol_name_regex();
2800       if (symbol_name_regex && !regex::match(symbol_name_regex, sym_name))
2801 	return false;
2802     }
2803   else
2804     no_symbol_name = true;
2805 
2806   // Consider the symbol version
2807   if (!get_symbol_version().empty())
2808     {
2809       if (sym_version != get_symbol_version())
2810 	return false;
2811     }
2812   else if (!get_symbol_version_regex_str().empty())
2813     {
2814       const regex_t_sptr symbol_version_regex =
2815 	priv_->get_symbol_version_regex();
2816       if (symbol_version_regex
2817 	  && !regex::match(symbol_version_regex, sym_version))
2818 	return false;
2819     }
2820   else
2821     no_symbol_version = true;
2822 
2823   if (no_symbol_name && no_symbol_version)
2824     return false;
2825 
2826   return true;
2827 }
2828 
2829 /// Evaluate the current function suppression specification on a given
2830 /// @ref elf_symbol and say if a report about a change involving this
2831 /// @ref elf_symbol should be suppressed or not.
2832 ///
2833 /// @param sym the @ref elf_symbol to evaluate this suppression
2834 /// specification against.
2835 ///
2836 /// @param k the kind of function change @p sym is supposed to have.
2837 ///
2838 /// @param ctxt the context of the current diff.
2839 ///
2840 /// @return true iff a report about a change involving the symbol @p
2841 /// sym should be suppressed.
2842 bool
suppresses_function_symbol(const elf_symbol_sptr sym,change_kind k,const diff_context_sptr ctxt)2843 function_suppression::suppresses_function_symbol(const elf_symbol_sptr sym,
2844 						 change_kind k,
2845 						 const diff_context_sptr ctxt)
2846 {return suppresses_function_symbol(sym.get(), k, ctxt);}
2847 
2848 /// Test if an instance of @ref suppression is an instance of @ref
2849 /// function_suppression.
2850 ///
2851 /// @param suppr the instance of @ref suppression to test for.
2852 ///
2853 /// @return if @p suppr is an instance of @ref function_suppression, then
2854 /// return the sub-object of the @p suppr of type @ref
2855 /// function_suppression, otherwise return a nil pointer.
2856 function_suppression_sptr
is_function_suppression(const suppression_sptr suppr)2857 is_function_suppression(const suppression_sptr suppr)
2858 {return dynamic_pointer_cast<function_suppression>(suppr);}
2859 
2860 /// The bitwise 'and' operator for the enum @ref
2861 /// function_suppression::change_kind.
2862 ///
2863 /// @param l the first operand of the 'and' operator.
2864 ///
2865 /// @param r the second operand of the 'and' operator.
2866 ///
2867 /// @return the result of 'and' operation on @p l and @p r.
2868 function_suppression::change_kind
operator &(function_suppression::change_kind l,function_suppression::change_kind r)2869 operator&(function_suppression::change_kind l,
2870 	  function_suppression::change_kind r)
2871 {
2872   return static_cast<function_suppression::change_kind>
2873     (static_cast<unsigned>(l) & static_cast<unsigned>(r));
2874 }
2875 
2876 /// The bitwise 'or' operator for the enum @ref
2877 /// function_suppression::change_kind.
2878 ///
2879 /// @param l the first operand of the 'or' operator.
2880 ///
2881 /// @param r the second operand of the 'or' operator.
2882 ///
2883 /// @return the result of 'or' operation on @p l and @p r.
2884 function_suppression::change_kind
operator |(function_suppression::change_kind l,function_suppression::change_kind r)2885 operator|(function_suppression::change_kind l,
2886 	  function_suppression::change_kind r)
2887 {
2888     return static_cast<function_suppression::change_kind>
2889       (static_cast<unsigned>(l) | static_cast<unsigned>(r));
2890 }
2891 
2892   /// Test whether if a given function suppression matches a function
2893   /// designated by a regular expression that describes its name.
2894   ///
2895   /// @param s the suppression specification to evaluate to see if it
2896   /// matches a given function name.
2897   ///
2898   /// @param fn_name the name of the function of interest.  Note that
2899   /// this name must be *non* qualified.
2900   ///
2901   /// @return true iff the suppression specification @p s matches the
2902   /// function whose name is @p fn_name.
2903 bool
suppression_matches_function_name(const suppr::function_suppression & s,const string & fn_name)2904 suppression_matches_function_name(const suppr::function_suppression& s,
2905 				  const string& fn_name)
2906 {
2907   if (regex_t_sptr regexp = s.priv_->get_name_regex())
2908     {
2909       if (!regex::match(regexp, fn_name))
2910 	return false;
2911     }
2912   else if (regex_t_sptr regexp = s.priv_->get_name_not_regex())
2913     {
2914       if (regex::match(regexp, fn_name))
2915 	return false;
2916     }
2917   else if (s.priv_->name_.empty())
2918     return false;
2919   else // if (!s.priv_->name_.empty())
2920     {
2921       if (s.priv_->name_ != fn_name)
2922 	return false;
2923     }
2924 
2925   return true;
2926 }
2927 
2928 /// Test whether if a given function suppression matches a function
2929 /// designated by a regular expression that describes its linkage
2930 /// name (symbol name).
2931 ///
2932 /// @param s the suppression specification to evaluate to see if it
2933 /// matches a given function linkage name
2934 ///
2935 /// @param fn_linkage_name the linkage name of the function of interest.
2936 ///
2937 /// @return true iff the suppression specification @p s matches the
2938 /// function whose linkage name is @p fn_linkage_name.
2939 bool
suppression_matches_function_sym_name(const suppr::function_suppression & s,const string & fn_linkage_name)2940 suppression_matches_function_sym_name(const suppr::function_suppression& s,
2941 				      const string& fn_linkage_name)
2942 {
2943   if (regex_t_sptr regexp = s.priv_->get_symbol_name_regex())
2944     {
2945       if (!regex::match(regexp, fn_linkage_name))
2946 	return false;
2947     }
2948   else if (regex_t_sptr regexp = s.priv_->get_symbol_name_not_regex())
2949     {
2950       if (regex::match(regexp, fn_linkage_name))
2951 	return false;
2952     }
2953   else if (s.priv_->symbol_name_.empty())
2954     return false;
2955   else // if (!s.priv_->symbol_name_.empty())
2956     {
2957       if (s.priv_->symbol_name_ != fn_linkage_name)
2958 	return false;
2959     }
2960 
2961   return true;
2962 }
2963 
2964 /// Test if a variable suppression matches a variable denoted by its name.
2965 ///
2966 /// @param s the variable suppression to consider.
2967 ///
2968 /// @param var_name the name of the variable to consider.
2969 ///
2970 /// @return true if the variable is matches by the suppression
2971 /// specification.
2972 bool
suppression_matches_variable_name(const suppr::variable_suppression & s,const string & var_name)2973 suppression_matches_variable_name(const suppr::variable_suppression& s,
2974 				  const string& var_name)
2975 {
2976   if (regex_t_sptr regexp = s.priv_->get_name_regex())
2977     {
2978       if (!regex::match(regexp, var_name))
2979 	return false;
2980     }
2981   else if (regex_t_sptr regexp = s.priv_->get_name_not_regex())
2982     {
2983       if (regex::match(regexp, var_name))
2984 	return false;
2985     }
2986   else if (s.priv_->name_.empty())
2987     return false;
2988   else // if (!s.priv_->name_.empty())
2989     {
2990       if (s.priv_->name_ != var_name)
2991 	return false;
2992     }
2993 
2994   return true;
2995 }
2996 
2997 /// Test if a variable suppression matches a variable denoted by its
2998 /// symbol name.
2999 ///
3000 /// @param s the variable suppression to consider.
3001 ///
3002 /// @param var_linkage_name the name of the variable to consider.
3003 ///
3004 /// @return true if the variable is matches by the suppression
3005 /// specification.
3006 bool
suppression_matches_variable_sym_name(const suppr::variable_suppression & s,const string & var_linkage_name)3007 suppression_matches_variable_sym_name(const suppr::variable_suppression& s,
3008 				      const string& var_linkage_name)
3009 {
3010   if (regex_t_sptr regexp = s.priv_->get_symbol_name_regex())
3011     {
3012       if (!regex::match(regexp, var_linkage_name))
3013 	return false;
3014     }
3015   else if (regex_t_sptr regexp =
3016 	   s.priv_->get_symbol_name_not_regex())
3017     {
3018       if (regex::match(regexp, var_linkage_name))
3019 	return false;
3020     }
3021   else if (s.priv_->symbol_name_.empty())
3022     return false;
3023   else // if (!s.priv_->symbol_name_.empty())
3024     {
3025       if (s.priv_->symbol_name_ != var_linkage_name)
3026 	return false;
3027     }
3028 
3029   return true;
3030 }
3031 
3032 /// Test if a type suppression matches a type designated by its fully
3033 /// qualified name.
3034 ///
3035 /// @param s the type suppression to consider.
3036 ///
3037 /// @param type_name the name of the type to consider.
3038 ///
3039 /// @return true iff the suppression s matches the type denoted by
3040 /// name @p type_name.
3041 bool
suppression_matches_type(const suppr::type_suppression & s,const string & type_name)3042 suppression_matches_type(const suppr::type_suppression& s,
3043 			 const string& type_name)
3044 {
3045   if (regex_t_sptr regexp = s.priv_->get_type_name_regex())
3046     {
3047       if (!regex::match(regexp, type_name))
3048 	return false;
3049     }
3050   else if (!s.get_type_name().empty())
3051     {
3052       if (s.get_type_name() != type_name)
3053 	return false;
3054     }
3055   else
3056     return false;
3057 
3058   return true;
3059 }
3060 
3061 /// Parse a string containing a parameter spec, build an instance of
3062 /// function_suppression::parameter_spec from it and return a pointer
3063 /// to that object.
3064 ///
3065 /// @return a shared pointer pointer to the newly built instance of
3066 /// function_suppression::parameter_spec.  If the parameter
3067 /// specification could not be parsed, return a nil object.
3068 static function_suppression::parameter_spec_sptr
read_parameter_spec_from_string(const string & str)3069 read_parameter_spec_from_string(const string& str)
3070 {
3071   string::size_type cur = 0;
3072   function_suppression::parameter_spec_sptr result;
3073 
3074   // skip leading white spaces.
3075   for (; cur < str.size(); ++cur)
3076     if (!isspace(str[cur]))
3077       break;
3078 
3079   // look for the parameter index
3080   string index_str;
3081   if (str[cur] == '\'')
3082     {
3083       ++cur;
3084       for (; cur < str.size(); ++cur)
3085 	if (!isdigit(str[cur]))
3086 	  break;
3087 	else
3088 	  index_str += str[cur];
3089     }
3090 
3091   // skip white spaces.
3092   for (; cur < str.size(); ++cur)
3093     if (!isspace(str[cur]))
3094       break;
3095 
3096   bool is_regex = false;
3097   if (str[cur] == '/')
3098     {
3099       is_regex = true;
3100       ++cur;
3101     }
3102 
3103   // look for the type name (regex)
3104   string type_name;
3105   for (; cur < str.size(); ++cur)
3106     if (!isspace(str[cur]))
3107       {
3108 	if (is_regex && str[cur] == '/')
3109 	  break;
3110 	type_name += str[cur];
3111       }
3112 
3113   if (is_regex && str[cur] == '/')
3114     ++cur;
3115 
3116   if (!index_str.empty() || !type_name.empty())
3117     {
3118       std::string type_name_regex;
3119       if (is_regex)
3120 	{
3121 	  type_name_regex = type_name;
3122 	  type_name.clear();
3123 	}
3124       function_suppression::parameter_spec* p =
3125 	new function_suppression::parameter_spec(atoi(index_str.c_str()),
3126 						 type_name, type_name_regex);
3127       result.reset(p);
3128     }
3129 
3130   return result;
3131 }
3132 
3133 /// Parse function suppression specification, build a resulting @ref
3134 /// function_suppression type and return a shared pointer to that
3135 /// object.
3136 ///
3137 /// @return a shared pointer to the newly built @ref
3138 /// function_suppression.  If the function suppression specification
3139 /// could not be parsed then a nil shared pointer is returned.
3140 static function_suppression_sptr
read_function_suppression(const ini::config::section & section)3141 read_function_suppression(const ini::config::section& section)
3142 {
3143   function_suppression_sptr result;
3144 
3145   if (section.get_name() != "suppress_function")
3146     return result;
3147 
3148   static const char *const sufficient_props[] = {
3149     "label",
3150     "file_name_regexp",
3151     "file_name_not_regexp",
3152     "soname_regexp",
3153     "soname_not_regexp",
3154     "name",
3155     "name_regexp",
3156     "name_not_regexp",
3157     "parameter",
3158     "return_type_name",
3159     "return_type_regexp",
3160     "symbol_name",
3161     "symbol_name_regexp",
3162     "symbol_name_not_regexp",
3163     "symbol_version",
3164     "symbol_version_regexp",
3165   };
3166   if (!check_sufficient_props(sufficient_props,
3167 			      sizeof(sufficient_props)/sizeof(char*),
3168 			      section))
3169     return result;
3170 
3171   ini::simple_property_sptr drop_artifact =
3172     is_simple_property(section.find_property("drop_artifact"));
3173   if (!drop_artifact)
3174     drop_artifact = is_simple_property(section.find_property("drop"));
3175 
3176   string drop_artifact_str = drop_artifact
3177     ? drop_artifact->get_value()->as_string()
3178     : "";
3179 
3180   ini::simple_property_sptr change_kind_prop =
3181     is_simple_property(section.find_property("change_kind"));
3182   string change_kind_str = change_kind_prop
3183     ? change_kind_prop->get_value()->as_string()
3184     : "";
3185 
3186   ini::simple_property_sptr label_prop =
3187     is_simple_property(section.find_property("label"));
3188   string label_str = label_prop
3189     ? label_prop->get_value()->as_string()
3190     : "";
3191 
3192   ini::simple_property_sptr file_name_regex_prop =
3193     is_simple_property(section.find_property("file_name_regexp"));
3194   string file_name_regex_str =
3195     file_name_regex_prop ? file_name_regex_prop->get_value()->as_string() : "";
3196 
3197   ini::simple_property_sptr file_name_not_regex_prop =
3198     is_simple_property(section.find_property("file_name_not_regexp"));
3199   string file_name_not_regex_str =
3200     file_name_not_regex_prop
3201     ? file_name_not_regex_prop->get_value()->as_string()
3202     : "";
3203 
3204   ini::simple_property_sptr soname_regex_prop =
3205     is_simple_property(section.find_property("soname_regexp"));
3206   string soname_regex_str =
3207     soname_regex_prop ? soname_regex_prop->get_value()->as_string() : "";
3208 
3209   ini::simple_property_sptr soname_not_regex_prop =
3210     is_simple_property(section.find_property("soname_not_regexp"));
3211   string soname_not_regex_str =
3212     soname_not_regex_prop
3213     ? soname_not_regex_prop->get_value()->as_string()
3214     : "";
3215 
3216   ini::simple_property_sptr name_prop =
3217     is_simple_property(section.find_property("name"));
3218   string name = name_prop
3219     ? name_prop->get_value()->as_string()
3220     : "";
3221 
3222   ini::simple_property_sptr name_regex_prop =
3223     is_simple_property(section.find_property("name_regexp"));
3224   string name_regex_str = name_regex_prop
3225     ? name_regex_prop->get_value()->as_string()
3226     : "";
3227 
3228   ini::simple_property_sptr name_not_regex_prop =
3229     is_simple_property(section.find_property("name_not_regexp"));
3230   string name_not_regex_str = name_not_regex_prop
3231     ? name_not_regex_prop->get_value()->as_string()
3232     : "";
3233 
3234   ini::simple_property_sptr return_type_name_prop =
3235     is_simple_property(section.find_property("return_type_name"));
3236   string return_type_name = return_type_name_prop
3237     ? return_type_name_prop->get_value()->as_string()
3238     : "";
3239 
3240   ini::simple_property_sptr return_type_regex_prop =
3241     is_simple_property(section.find_property("return_type_regexp"));
3242   string return_type_regex_str = return_type_regex_prop
3243     ? return_type_regex_prop->get_value()->as_string()
3244     : "";
3245 
3246   ini::simple_property_sptr sym_name_prop =
3247     is_simple_property(section.find_property("symbol_name"));
3248   string sym_name = sym_name_prop
3249     ? sym_name_prop->get_value()->as_string()
3250     : "";
3251 
3252   ini::simple_property_sptr sym_name_regex_prop =
3253     is_simple_property(section.find_property("symbol_name_regexp"));
3254   string sym_name_regex_str = sym_name_regex_prop
3255     ? sym_name_regex_prop->get_value()->as_string()
3256     : "";
3257 
3258   ini::simple_property_sptr sym_name_not_regex_prop =
3259     is_simple_property(section.find_property("symbol_name_not_regexp"));
3260   string sym_name_not_regex_str = sym_name_not_regex_prop
3261     ? sym_name_not_regex_prop->get_value()->as_string()
3262     : "";
3263 
3264   ini::simple_property_sptr sym_ver_prop =
3265     is_simple_property(section.find_property("symbol_version"));
3266   string sym_version = sym_ver_prop
3267     ? sym_ver_prop->get_value()->as_string()
3268     : "";
3269 
3270   ini::simple_property_sptr sym_ver_regex_prop =
3271     is_simple_property(section.find_property("symbol_version_regexp"));
3272   string sym_ver_regex_str = sym_ver_regex_prop
3273     ? sym_ver_regex_prop->get_value()->as_string()
3274     : "";
3275 
3276   ini::simple_property_sptr allow_other_aliases_prop =
3277     is_simple_property(section.find_property("allow_other_aliases"));
3278   string allow_other_aliases = allow_other_aliases_prop
3279     ? allow_other_aliases_prop->get_value()->as_string()
3280     : "";
3281 
3282   function_suppression::parameter_spec_sptr parm;
3283   function_suppression::parameter_specs_type parms;
3284   for (ini::config::properties_type::const_iterator p =
3285 	 section.get_properties().begin();
3286        p != section.get_properties().end();
3287        ++p)
3288     if ((*p)->get_name() == "parameter")
3289       {
3290 	ini::simple_property_sptr prop = is_simple_property(*p);
3291 	ABG_ASSERT(prop);
3292 	if ((parm = read_parameter_spec_from_string
3293 	      (prop->get_value()->as_string())))
3294 	  parms.push_back(parm);
3295       }
3296 
3297   result.reset(new function_suppression(label_str,
3298 					name,
3299 					name_regex_str,
3300 					return_type_name,
3301 					return_type_regex_str,
3302 					parms,
3303 					sym_name,
3304 					sym_name_regex_str,
3305 					sym_version,
3306 					sym_ver_regex_str));
3307 
3308   if ((drop_artifact_str == "yes" || drop_artifact_str == "true")
3309       && (!name.empty()
3310 	  || !name_regex_str.empty()
3311 	  || !name_not_regex_str.empty()
3312 	  || !sym_name.empty()
3313 	  || !sym_name_regex_str.empty()
3314 	  || !sym_name_not_regex_str.empty()))
3315     result->set_drops_artifact_from_ir(true);
3316 
3317   if (!change_kind_str.empty())
3318     result->set_change_kind
3319       (function_suppression::parse_change_kind(change_kind_str));
3320 
3321   if (!allow_other_aliases.empty())
3322     result->set_allow_other_aliases(allow_other_aliases == "yes"
3323 				    || allow_other_aliases == "true");
3324 
3325   if (!name_not_regex_str.empty())
3326     result->set_name_not_regex_str(name_not_regex_str);
3327 
3328   if (!sym_name_not_regex_str.empty())
3329     result->set_symbol_name_not_regex_str(sym_name_not_regex_str);
3330 
3331   if (!file_name_regex_str.empty())
3332     result->set_file_name_regex_str(file_name_regex_str);
3333 
3334   if (!file_name_not_regex_str.empty())
3335     result->set_file_name_not_regex_str(file_name_not_regex_str);
3336 
3337   if (!soname_regex_str.empty())
3338     result->set_soname_regex_str(soname_regex_str);
3339 
3340   if (!soname_not_regex_str.empty())
3341     result->set_soname_not_regex_str(soname_not_regex_str);
3342 
3343   return result;
3344 }
3345 
3346 // </function_suppression stuff>
3347 
3348 // <variable_suppression stuff>
3349 
3350 /// Constructor for the @ref variable_suppression type.
3351 ///
3352 /// @param label an informative text string that the evalution code
3353 /// might use to designate this variable suppression specification in
3354 /// error messages.  This parameter might be empty, in which case it's
3355 /// ignored at evaluation time.
3356 ///
3357 /// @param name the name of the variable the user wants the current
3358 /// specification to designate.  This parameter might be empty, in
3359 /// which case it's ignored at evaluation time.
3360 ///
3361 /// @param name_regex_str if @p name is empty, this parameter is a
3362 /// regular expression for a family of names of variables the user
3363 /// wants the current specification to designate.  If @p name is not
3364 /// empty, then this parameter is ignored at evaluation time.  This
3365 /// parameter might be empty, in which case it's ignored at evaluation
3366 /// time.
3367 ///
3368 /// @param symbol_name the name of the symbol of the variable the user
3369 /// wants the current specification to designate.  This parameter
3370 /// might be empty, in which case it's ignored at evaluation time.
3371 ///
3372 /// @param symbol_name_str if @p symbol_name is empty, this parameter
3373 /// is a regular expression for a family of names of symbols of
3374 /// variables the user wants the current specification to designate.
3375 /// If @p symbol_name is not empty, then this parameter is ignored at
3376 /// evaluation time.  This parameter might be empty, in which case
3377 /// it's ignored at evaluation time.
3378 ///
3379 /// @param symbol_version the version of the symbol of the variable
3380 /// the user wants the current specification to designate.  This
3381 /// parameter might be empty, in which case it's ignored at evaluation
3382 /// time.
3383 ///
3384 /// @param symbol_version_regex if @p symbol_version is empty, then
3385 /// this parameter is a regular expression for a family of versions of
3386 /// symbol for the variables the user wants the current specification
3387 /// to designate.  If @p symbol_version is not empty, then this
3388 /// parameter is ignored at evaluation time.  This parameter might be
3389 /// empty, in which case it's ignored at evaluation time.
3390 ///
3391 /// @param type_name the name of the type of the variable the user
3392 /// wants the current specification to designate.  This parameter
3393 /// might be empty, in which case it's ignored at evaluation time.
3394 ///
3395 /// @param type_name_regex_str if @p type_name is empty, then this
3396 /// parameter is a regular expression for a family of type names of
3397 /// variables the user wants the current specification to designate.
3398 /// If @p type_name is not empty, then this parameter is ignored at
3399 /// evluation time.  This parameter might be empty, in which case it's
3400 /// 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)3401 variable_suppression::variable_suppression(const string& label,
3402 					   const string& name,
3403 					   const string& name_regex_str,
3404 					   const string& symbol_name,
3405 					   const string& symbol_name_regex_str,
3406 					   const string& symbol_version,
3407 					   const string& symbol_version_regex,
3408 					   const string& type_name,
3409 					   const string& type_name_regex_str)
3410   : suppression_base(label),
3411     priv_(new priv(name, name_regex_str,
3412 		   symbol_name, symbol_name_regex_str,
3413 		   symbol_version, symbol_version_regex,
3414 		   type_name, type_name_regex_str))
3415 {}
3416 
3417 /// Virtual destructor for the @erf variable_suppression type.
3418 /// variable_suppression type.
~variable_suppression()3419 variable_suppression::~variable_suppression()
3420 {}
3421 
3422 /// Parses a string containing the content of the "change-kind"
3423 /// property and returns the an instance of @ref
3424 /// variable_suppression::change_kind as a result.
3425 ///
3426 /// @param s the string to parse.
3427 ///
3428 /// @return the resulting @ref variable_suppression::change_kind.
3429 variable_suppression::change_kind
parse_change_kind(const string & s)3430 variable_suppression::parse_change_kind(const string& s)
3431 {
3432   if (s == "variable-subtype-change")
3433     return VARIABLE_SUBTYPE_CHANGE_KIND;
3434   else if (s == "added-variable")
3435     return ADDED_VARIABLE_CHANGE_KIND;
3436   else if (s == "deleted-variable")
3437     return DELETED_VARIABLE_CHANGE_KIND;
3438   else if (s == "all")
3439     return ALL_CHANGE_KIND;
3440   else
3441     return UNDEFINED_CHANGE_KIND;
3442 }
3443 
3444 /// Getter of the "change_king" property.
3445 ///
3446 /// @return the value of the "change_kind" property.
3447 variable_suppression::change_kind
get_change_kind() const3448 variable_suppression::get_change_kind() const
3449 {return priv_->change_kind_;}
3450 
3451 /// Setter of the "change_kind" property.
3452 ///
3453 /// @param k the new value of of the change_kind.
3454 void
set_change_kind(change_kind k)3455 variable_suppression::set_change_kind(change_kind k)
3456 {priv_->change_kind_ = k;}
3457 
3458 /// Getter for the name of the variable the user wants the current
3459 /// specification to designate.  This property might be empty, in
3460 /// which case it's ignored at evaluation time.
3461 ///
3462 /// @return the name of the variable.
3463 const string&
get_name() const3464 variable_suppression::get_name() const
3465 {return priv_->name_;}
3466 
3467 /// Setter for the name of the variable the user wants the current
3468 /// specification to designate.  This property might be empty, in
3469 /// which case it's ignored at evaluation time.
3470 ///
3471 /// @param n the new name of the variable to set.
3472 void
set_name(const string & n)3473 variable_suppression::set_name(const string& n)
3474 {priv_->name_ = n;}
3475 
3476 /// Getter for the regular expression for a family of names of
3477 /// variables the user wants the current specification to designate.
3478 /// If the variable name as returned by
3479 /// variable_suppression::get_name() is not empty, then this property
3480 /// is ignored at evaluation time.  This property might be empty, in
3481 /// which case it's ignored at evaluation time.
3482 ///
3483 /// @return the regular expression for the variable name.
3484 const string&
get_name_regex_str() const3485 variable_suppression::get_name_regex_str() const
3486 {return priv_->name_regex_str_;}
3487 
3488 /// Setter for the regular expression for a family of names of
3489 /// variables the user wants the current specification to designate.
3490 /// If the variable name as returned by
3491 /// variable_suppression::get_name() is not empty, then this property
3492 /// is ignored at evaluation time.  This property might be empty, in
3493 /// which case it's ignored at evaluation time.
3494 ///
3495 /// @param r the new regular expression for the variable name.
3496 void
set_name_regex_str(const string & r)3497 variable_suppression::set_name_regex_str(const string& r)
3498 {priv_->name_regex_str_ = r;}
3499 
3500 /// Getter for the "name_not_regexp" property of the specification.
3501 ///
3502 /// @return the value of the "name_not_regexp" property.
3503 const string&
get_name_not_regex_str() const3504 variable_suppression::get_name_not_regex_str() const
3505 {return priv_->name_not_regex_str_;}
3506 
3507 /// Setter for the "name_not_regexp" property of the specification.
3508 ///
3509 /// @param r the new value of the "name_not_regexp" property.
3510 void
set_name_not_regex_str(const string & r)3511 variable_suppression::set_name_not_regex_str(const string& r)
3512 {priv_->name_not_regex_str_ = r;}
3513 
3514 /// Getter for the name of the symbol of the variable the user wants
3515 /// the current specification to designate.
3516 ///
3517 /// This property might be empty, in which case it is ignored at
3518 /// evaluation time.
3519 ///
3520 /// @return the name of the symbol of the variable.
3521 const string&
get_symbol_name() const3522 variable_suppression::get_symbol_name() const
3523 {return priv_->symbol_name_;}
3524 
3525 /// Setter for the name of the symbol of the variable the user wants
3526 /// the current specification to designate.
3527 ///
3528 /// This property might be empty, in which case it is ignored at
3529 /// evaluation time.
3530 ///
3531 /// @param n the new name of the symbol of the variable.
3532 void
set_symbol_name(const string & n)3533 variable_suppression::set_symbol_name(const string& n)
3534 {priv_->symbol_name_ = n;}
3535 
3536 /// Getter of the regular expression for a family of symbol names of
3537 /// the variables this specification is about to designate.
3538 ///
3539 /// This property might be empty, in which case it's ignored at
3540 /// evaluation time.  Otherwise, it is taken in account iff the
3541 /// property returned by variable_suppression::get_symbol_name() is
3542 /// empty.
3543 ///
3544 /// @return the regular expression for a symbol name of the variable.
3545 const string&
get_symbol_name_regex_str() const3546 variable_suppression::get_symbol_name_regex_str() const
3547 {return priv_->symbol_name_regex_str_;}
3548 
3549 /// Setter of the regular expression for a family of symbol names of
3550 /// the variables this specification is about to designate.
3551 ///
3552 /// This property might be empty, in which case it's ignored at
3553 /// evaluation time.  Otherwise, it is taken in account iff the
3554 /// property returned by variable_suppression::get_symbol_name() is
3555 /// empty.
3556 ///
3557 /// @param r the regular expression for a symbol name of the variable.
3558 void
set_symbol_name_regex_str(const string & r)3559 variable_suppression::set_symbol_name_regex_str(const string& r)
3560 {priv_->symbol_name_regex_str_ = r;}
3561 
3562 /// Getter for a regular expression for a family of names of symbols
3563 /// of variables the user wants this specification to designate.
3564 ///
3565 /// If a symbol name is matched by this regular expression, then the
3566 /// suppression specification will *NOT* suppress the symbol.
3567 ///
3568 /// If the symbol name as returned by
3569 /// variable_suppression::get_symbol_name() is not empty, then this
3570 /// property is ignored at specification evaluation time.
3571 ///
3572 /// This property might be empty, in which case it's ignored at
3573 /// evaluation time.
3574 ///
3575 /// @return the regular expression string for a family of names of
3576 /// symbols that is to be *NOT* suppressed by this suppression specification.
3577 const string&
get_symbol_name_not_regex_str() const3578 variable_suppression::get_symbol_name_not_regex_str() const
3579 {return priv_->symbol_name_not_regex_str_;}
3580 
3581 /// Setter for a regular expression for a family of names of symbols
3582 /// of variables the user wants this specification to designate.
3583 ///
3584 /// If a symbol name is matched by this regular expression, then the
3585 /// suppression specification will *NOT* suppress the symbol.
3586 ///
3587 /// If the symbol name as returned by
3588 /// variable_suppression::get_symbol_name() is not empty, then this
3589 /// property is ignored at specification evaluation time.
3590 ///
3591 /// This property might be empty, in which case it's ignored at
3592 /// evaluation time.
3593 ///
3594 /// @param the new regular expression string for a family of names of
3595 /// symbols that is to be *NOT* suppressed by this suppression
3596 /// specification.
3597 void
set_symbol_name_not_regex_str(const string & r)3598 variable_suppression::set_symbol_name_not_regex_str(const string& r)
3599 {priv_->symbol_name_not_regex_str_ = r;}
3600 
3601 /// Getter for the version of the symbol of the variable the user
3602 /// wants the current specification to designate.  This property might
3603 /// be empty, in which case it's ignored at evaluation time.
3604 ///
3605 /// @return the symbol version of the variable.
3606 const string&
get_symbol_version() const3607 variable_suppression::get_symbol_version() const
3608 {return priv_->symbol_version_;}
3609 
3610 /// Setter for the version of the symbol of the variable the user
3611 /// wants the current specification to designate.  This property might
3612 /// be empty, in which case it's ignored at evaluation time.
3613 ///
3614 /// @return the new symbol version of the variable.
3615 void
set_symbol_version(const string & v)3616 variable_suppression::set_symbol_version(const string& v)
3617 {priv_->symbol_version_ = v;}
3618 
3619 /// Getter of the regular expression for a family of versions of
3620 /// symbol for the variables the user wants the current specification
3621 /// to designate.  If @p symbol_version is not empty, then this
3622 /// property is ignored at evaluation time.  This property might be
3623 /// empty, in which case it's ignored at evaluation time.
3624 ///
3625 /// @return the regular expression of the symbol version of the
3626 /// variable.
3627 const string&
get_symbol_version_regex_str() const3628 variable_suppression::get_symbol_version_regex_str() const
3629 {return priv_->symbol_version_regex_str_;}
3630 
3631 /// Setter of the regular expression for a family of versions of
3632 /// symbol for the variables the user wants the current specification
3633 /// to designate.  If @p symbol_version is not empty, then this
3634 /// property is ignored at evaluation time.  This property might be
3635 /// empty, in which case it's ignored at evaluation time.
3636 ///
3637 /// @param v the new regular expression of the symbol version of the
3638 /// variable.
3639 void
set_symbol_version_regex_str(const string & r)3640 variable_suppression::set_symbol_version_regex_str(const string& r)
3641 {priv_->symbol_version_regex_str_ = r;}
3642 
3643 /// Getter for the name of the type of the variable the user wants the
3644 /// current specification to designate.
3645 ///
3646 /// This property might be empty, in which case it's ignored at
3647 /// evaluation time.
3648 ///
3649 /// @return the name of the variable type.
3650 const string&
get_type_name() const3651 variable_suppression::get_type_name() const
3652 {return priv_->type_name_;}
3653 
3654 /// Setter for the name of the type of the variable the user wants the
3655 /// current specification to designate.
3656 ///
3657 /// This property might be empty, in which case it's ignored at
3658 /// evaluation time.
3659 ///
3660 /// @param n the new name of the variable type.
3661 void
set_type_name(const string & n)3662 variable_suppression::set_type_name(const string& n)
3663 {priv_->type_name_ = n;}
3664 
3665 /// Getter for the regular expression for a family of type names of
3666 /// variables the user wants the current specification to designate.
3667 ///
3668 /// If the type name as returned by
3669 /// variable_suppression::get_type_name() is not empty, then this
3670 /// property is ignored at evaluation time.  This property might be
3671 /// empty, in which case it's ignored at evaluation time.
3672 ///
3673 /// @return the regular expression of the variable type name.
3674 const string&
get_type_name_regex_str() const3675 variable_suppression::get_type_name_regex_str() const
3676 {return priv_->type_name_regex_str_;}
3677 
3678 /// Setter for the regular expression for a family of type names of
3679 /// variables the user wants the current specification to designate.
3680 ///
3681 /// If the type name as returned by
3682 /// variable_suppression::get_type_name() is not empty, then this
3683 /// property is ignored at evaluation time.  This property might be
3684 /// empty, in which case it's ignored at evaluation time.
3685 ///
3686 /// @param r the regular expression of the variable type name.
3687 void
set_type_name_regex_str(const string & r)3688 variable_suppression::set_type_name_regex_str(const string& r)
3689 {priv_->type_name_regex_str_ = r;}
3690 
3691 /// Evaluate this suppression specification on a given diff node and
3692 /// say if the diff node should be suppressed or not.
3693 ///
3694 /// @param diff the diff node to evaluate this suppression
3695 /// specification against.
3696 ///
3697 /// @return true if @p diff should be suppressed.
3698 bool
suppresses_diff(const diff * diff) const3699 variable_suppression::suppresses_diff(const diff* diff) const
3700 {
3701   const var_diff* d = is_var_diff(diff);
3702   if (!d)
3703     return false;
3704 
3705   var_decl_sptr fv = is_var_decl(is_decl(d->first_subject())),
3706     sv = is_var_decl(is_decl(d->second_subject()));
3707 
3708   ABG_ASSERT(fv && sv);
3709 
3710   return (suppresses_variable(fv,
3711 			      VARIABLE_SUBTYPE_CHANGE_KIND,
3712 			      diff->context())
3713 	  || suppresses_variable(sv,
3714 				 VARIABLE_SUBTYPE_CHANGE_KIND,
3715 				 diff->context()));
3716 }
3717 
3718 /// Evaluate the current variable suppression specification on a given
3719 /// @ref var_decl and say if a report about a change involving this
3720 /// @ref var_decl should be suppressed or not.
3721 ///
3722 /// @param var the @ref var_decl to evaluate this suppression
3723 /// specification against.
3724 ///
3725 /// @param k the kind of variable change @p var is supposed to have.
3726 ///
3727 /// @param ctxt the context of the current diff.
3728 ///
3729 /// @return true iff a report about a change involving the variable @p
3730 /// var should be suppressed.
3731 bool
suppresses_variable(const var_decl * var,change_kind k,const diff_context_sptr ctxt) const3732 variable_suppression::suppresses_variable(const var_decl* var,
3733 					  change_kind k,
3734 					  const diff_context_sptr ctxt) const
3735 {
3736   if (!(get_change_kind() & k))
3737     return false;
3738 
3739   // Check if the name and soname of the binaries match
3740   if (ctxt)
3741     {
3742       // Check if the name of the binaries match the current
3743       // suppr spec
3744       if (!names_of_binaries_match(*this, *ctxt))
3745 	if (has_file_name_related_property())
3746 	  return false;
3747 
3748       // Check if the soname of the binaries match the current suppr
3749       // spec
3750       if (!sonames_of_binaries_match(*this, *ctxt))
3751 	if (has_soname_related_property())
3752 	  return false;
3753     }
3754 
3755   string var_name = var->get_qualified_name();
3756 
3757   // Check for "name" property match.
3758   if (!get_name().empty())
3759     {
3760       if (get_name() != var_name)
3761 	return false;
3762     }
3763   else
3764     {
3765       // If the "name" property is empty, then consider checking for the
3766       // "name_regex" and "name_not_regex" properties match
3767       if (get_name().empty())
3768 	{
3769 	  const regex_t_sptr name_regex = priv_->get_name_regex();
3770 	  if (name_regex && !regex::match(name_regex, var_name))
3771 	    return false;
3772 
3773 	  const regex_t_sptr name_not_regex = priv_->get_name_not_regex();
3774 	  if (name_not_regex && regex::match(name_not_regex, var_name))
3775 	    return false;
3776 	}
3777     }
3778 
3779   // Check for the symbol_name, symbol_name_regex and
3780   // symbol_name_not_regex property match.
3781   string var_sym_name = var->get_symbol() ? var->get_symbol()->get_name() : "";
3782   if (!get_symbol_name().empty())
3783     {
3784       if (get_symbol_name() != var_sym_name)
3785 	return false;
3786     }
3787   else
3788     {
3789       const regex_t_sptr sym_name_regex = priv_->get_symbol_name_regex();
3790       if (sym_name_regex && !regex::match(sym_name_regex, var_sym_name))
3791 	return false;
3792 
3793       const regex_t_sptr sym_name_not_regex =
3794 	priv_->get_symbol_name_not_regex();
3795       if (sym_name_not_regex && regex::match(sym_name_not_regex, var_sym_name))
3796 	return false;
3797     }
3798 
3799   // Check for symbol_version and symbol_version_regexp property match
3800   string var_sym_version =
3801     var->get_symbol() ? var->get_symbol()->get_version().str() : "";
3802   if (!get_symbol_version().empty())
3803     {
3804       if (get_symbol_version() != var_sym_version)
3805 	return false;
3806     }
3807   else
3808     {
3809       const regex_t_sptr symbol_version_regex =
3810 	priv_->get_symbol_version_regex();
3811       if (symbol_version_regex
3812 	  && !regex::match(symbol_version_regex, var_sym_version))
3813 	return false;
3814     }
3815 
3816   // Check for the "type_name" and type_name_regex properties match.
3817   string var_type_name =
3818     get_type_declaration(var->get_type())->get_qualified_name();
3819 
3820   if (!get_type_name().empty())
3821     {
3822       if (get_type_name() != var_type_name)
3823 	return false;
3824     }
3825   else
3826     {
3827       if (get_type_name().empty())
3828 	{
3829 	  const regex_t_sptr type_name_regex = priv_->get_type_name_regex();
3830 	  if (type_name_regex && !regex::match(type_name_regex, var_type_name))
3831 	    return false;
3832 	}
3833     }
3834 
3835   return true;
3836 }
3837 
3838 /// Evaluate the current variable suppression specification on a given
3839 /// @ref var_decl and say if a report about a change involving this
3840 /// @ref var_decl should be suppressed or not.
3841 ///
3842 /// @param var the @ref var_decl to evaluate this suppression
3843 /// specification against.
3844 ///
3845 /// @param k the kind of variable change @p var is supposed to have.
3846 ///
3847 /// @param ctxt the context of the current diff.
3848 ///
3849 /// @return true iff a report about a change involving the variable @p
3850 /// var should be suppressed.
3851 bool
suppresses_variable(const var_decl_sptr var,change_kind k,const diff_context_sptr ctxt) const3852 variable_suppression::suppresses_variable(const var_decl_sptr var,
3853 					  change_kind k,
3854 					  const diff_context_sptr ctxt) const
3855 {return suppresses_variable(var.get(), k, ctxt);}
3856 
3857 /// Evaluate the current variable suppression specification on a given
3858 /// @ref elf_symbol and say if a report about a change involving this
3859 /// @ref elf_symbol should be suppressed or not.
3860 ///
3861 /// @param sym the @ref elf_symbol to evaluate this suppression
3862 /// specification against.
3863 ///
3864 /// @param k the kind of variable change @p sym is supposed to have.
3865 ///
3866 /// @param ctxt the context of the current diff.
3867 ///
3868 /// @return true iff a report about a change involving the symbol @p
3869 /// sym should be suppressed.
3870 bool
suppresses_variable_symbol(const elf_symbol * sym,change_kind k,const diff_context_sptr ctxt) const3871 variable_suppression::suppresses_variable_symbol(const elf_symbol* sym,
3872 						 change_kind k,
3873 						 const diff_context_sptr ctxt) const
3874 {
3875   if (!sym)
3876     return false;
3877 
3878   if (!(get_change_kind() & k))
3879     return false;
3880 
3881   if (!sym->is_variable())
3882     return false;
3883 
3884   ABG_ASSERT(k & ADDED_VARIABLE_CHANGE_KIND
3885 	 || k & DELETED_VARIABLE_CHANGE_KIND);
3886 
3887   // Check if the name and soname of the binaries match the current
3888   // suppr spec.
3889   if (ctxt)
3890     {
3891       // Check if the name of the binaries match the current suppr
3892       // spec
3893       if (!names_of_binaries_match(*this, *ctxt))
3894 	if (has_file_name_related_property())
3895 	  return false;
3896 
3897       // Check if the soname of the binaries match the current suppr spec
3898       if (!sonames_of_binaries_match(*this, *ctxt))
3899 	if (has_soname_related_property())
3900 	  return false;
3901     }
3902 
3903   string sym_name = sym->get_name(), sym_version = sym->get_version().str();
3904 
3905   bool no_symbol_name = false, no_symbol_version = false;
3906 
3907   // Consider the symbol name
3908   if (!get_name().empty())
3909     {
3910       if (get_name() != sym_name)
3911 	return false;
3912     }
3913   else if (!get_symbol_name().empty())
3914     {
3915       if (get_symbol_name() != sym_name)
3916 	return false;
3917     }
3918   else if (!get_symbol_name_regex_str().empty())
3919     {
3920       const regex_t_sptr sym_name_regex = priv_->get_symbol_name_regex();
3921       if (sym_name_regex && !regex::match(sym_name_regex, sym_name))
3922 	return false;
3923     }
3924   else
3925     no_symbol_name = true;
3926 
3927   // Consider the symbol version.
3928   if (!get_symbol_version().empty())
3929     {
3930       if (get_symbol_version() != sym_version)
3931 	return false;
3932     }
3933   else if (!get_symbol_version_regex_str().empty())
3934     {
3935       const regex_t_sptr symbol_version_regex =
3936 	priv_->get_symbol_version_regex();
3937       if (symbol_version_regex
3938 	  && !regex::match(symbol_version_regex, sym_version))
3939 	return false;
3940     }
3941   else
3942     no_symbol_version = true;
3943 
3944   if (no_symbol_name && no_symbol_version)
3945     return false;
3946 
3947   return true;
3948 }
3949 
3950 /// Evaluate the current variable suppression specification on a given
3951 /// @ref elf_symbol and say if a report about a change involving this
3952 /// @ref elf_symbol should be suppressed or not.
3953 ///
3954 /// @param sym the @ref elf_symbol to evaluate this suppression
3955 /// specification against.
3956 ///
3957 /// @param k the kind of variable change @p sym is supposed to have.
3958 ///
3959 /// @param ctxt the context of the current diff.
3960 ///
3961 /// @return true iff a report about a change involving the symbol @p
3962 /// sym should be suppressed.
3963 bool
suppresses_variable_symbol(const elf_symbol_sptr sym,change_kind k,const diff_context_sptr ctxt) const3964 variable_suppression::suppresses_variable_symbol(const elf_symbol_sptr sym,
3965 						 change_kind k,
3966 						 const diff_context_sptr ctxt) const
3967 {return suppresses_variable_symbol(sym.get(), k, ctxt);}
3968 
3969 /// Test if an instance of @ref suppression is an instance of @ref
3970 /// variable_suppression.
3971 ///
3972 /// @param suppr the instance of @ref suppression to test for.
3973 ///
3974 /// @return if @p suppr is an instance of @ref variable_suppression, then
3975 /// return the sub-object of the @p suppr of type @ref
3976 /// variable_suppression, otherwise return a nil pointer.
3977 variable_suppression_sptr
is_variable_suppression(const suppression_sptr s)3978 is_variable_suppression(const suppression_sptr s)
3979 {return dynamic_pointer_cast<variable_suppression>(s);}
3980 
3981 /// The bitwise 'and' operator for the enum @ref
3982 /// variable_suppression::change_kind.
3983 ///
3984 /// @param l the first operand of the 'and' operator.
3985 ///
3986 /// @param r the second operand of the 'and' operator.
3987 ///
3988 /// @return the result of 'and' operation on @p l and @p r.
3989 variable_suppression::change_kind
operator &(variable_suppression::change_kind l,variable_suppression::change_kind r)3990 operator&(variable_suppression::change_kind l,
3991 	  variable_suppression::change_kind r)
3992 {
3993   return static_cast<variable_suppression::change_kind>
3994     (static_cast<unsigned>(l) & static_cast<unsigned>(r));
3995 }
3996 
3997 /// The bitwise 'or' operator for the enum @ref
3998 /// variable_suppression::change_kind.
3999 ///
4000 /// @param l the first operand of the 'or' operator.
4001 ///
4002 /// @param r the second operand of the 'or' operator.
4003 ///
4004 /// @return the result of 'or' operation on @p l and @p r.
4005 variable_suppression::change_kind
operator |(variable_suppression::change_kind l,variable_suppression::change_kind r)4006 operator|(variable_suppression::change_kind l,
4007 	  variable_suppression::change_kind r)
4008 {
4009     return static_cast<variable_suppression::change_kind>
4010     (static_cast<unsigned>(l) | static_cast<unsigned>(r));
4011 }
4012 
4013 /// Parse variable suppression specification, build a resulting @ref
4014 /// variable_suppression type and return a shared pointer to that
4015 /// object.
4016 ///
4017 /// @return a shared pointer to the newly built @ref
4018 /// variable_suppression.  If the variable suppression specification
4019 /// could not be parsed then a nil shared pointer is returned.
4020 static variable_suppression_sptr
read_variable_suppression(const ini::config::section & section)4021 read_variable_suppression(const ini::config::section& section)
4022 {
4023   variable_suppression_sptr result;
4024 
4025   if (section.get_name() != "suppress_variable")
4026     return result;
4027 
4028   static const char *const sufficient_props[] = {
4029     "label",
4030     "file_name_regexp",
4031     "file_name_not_regexp",
4032     "soname_regexp",
4033     "soname_not_regexp",
4034     "name",
4035     "name_regexp",
4036     "name_not_regexp",
4037     "symbol_name",
4038     "symbol_name_regexp",
4039     "symbol_name_not_regexp",
4040     "symbol_version",
4041     "symbol_version_regexp",
4042     "type_name",
4043     "type_name_regexp",
4044   };
4045   if (!check_sufficient_props(sufficient_props,
4046 			      sizeof(sufficient_props)/sizeof(char*),
4047 			      section))
4048     return result;
4049 
4050   ini::simple_property_sptr drop_artifact =
4051     is_simple_property(section.find_property("drop_artifact"));
4052   if (!drop_artifact)
4053     drop_artifact = is_simple_property(section.find_property("drop"));
4054 
4055   string drop_artifact_str = drop_artifact
4056     ? drop_artifact->get_value()->as_string()
4057     : "";
4058 
4059   ini::simple_property_sptr change_kind_prop =
4060     is_simple_property(section.find_property("change_kind"));
4061   string change_kind_str = change_kind_prop
4062     ? change_kind_prop->get_value()->as_string()
4063     : "";
4064 
4065   ini::simple_property_sptr label_prop =
4066     is_simple_property(section.find_property("label"));
4067   string label_str = (label_prop
4068 		      ? label_prop->get_value()->as_string()
4069 		      : "");
4070 
4071   ini::simple_property_sptr file_name_regex_prop =
4072     is_simple_property(section.find_property("file_name_regexp"));
4073   string file_name_regex_str =
4074     file_name_regex_prop ? file_name_regex_prop->get_value()->as_string() : "";
4075 
4076  ini::simple_property_sptr file_name_not_regex_prop =
4077     is_simple_property(section.find_property("file_name_not_regexp"));
4078   string file_name_not_regex_str =
4079     file_name_not_regex_prop
4080     ? file_name_not_regex_prop->get_value()->as_string()
4081     : "";
4082 
4083   ini::simple_property_sptr soname_regex_prop =
4084     is_simple_property(section.find_property("soname_regexp"));
4085   string soname_regex_str =
4086     soname_regex_prop ? soname_regex_prop->get_value()->as_string() : "";
4087 
4088   ini::simple_property_sptr soname_not_regex_prop =
4089     is_simple_property(section.find_property("soname_not_regexp"));
4090   string soname_not_regex_str =
4091     soname_not_regex_prop
4092     ? soname_not_regex_prop->get_value()->as_string()
4093     : "";
4094 
4095   ini::simple_property_sptr name_prop =
4096     is_simple_property(section.find_property("name"));
4097   string name_str = (name_prop
4098 		     ? name_prop->get_value()->as_string()
4099 		     : "");
4100 
4101   ini::simple_property_sptr name_regex_prop =
4102     is_simple_property(section.find_property("name_regexp"));
4103   string name_regex_str = (name_regex_prop
4104 			   ? name_regex_prop->get_value()->as_string()
4105 			   : "");
4106 
4107   ini::simple_property_sptr name_not_regex_prop =
4108     is_simple_property(section.find_property("name_not_regexp"));
4109   string name_not_regex_str = name_not_regex_prop
4110     ? name_not_regex_prop->get_value()->as_string()
4111     : "";
4112 
4113   ini::simple_property_sptr sym_name_prop =
4114     is_simple_property(section.find_property("symbol_name"));
4115   string symbol_name = (sym_name_prop
4116 			? sym_name_prop->get_value()->as_string()
4117 			: "");
4118 
4119   ini::simple_property_sptr sym_name_regex_prop =
4120     is_simple_property(section.find_property("symbol_name_regexp"));
4121   string symbol_name_regex_str = sym_name_regex_prop
4122     ? sym_name_regex_prop->get_value()->as_string()
4123     : "";
4124 
4125   ini::simple_property_sptr sym_name_not_regex_prop =
4126     is_simple_property(section.find_property("symbol_name_not_regexp"));
4127   string symbol_name_not_regex_str = sym_name_not_regex_prop
4128     ? sym_name_not_regex_prop->get_value()->as_string()
4129     : "";
4130 
4131   ini::simple_property_sptr sym_version_prop =
4132     is_simple_property(section.find_property("symbol_version"));
4133   string symbol_version = sym_version_prop
4134     ? sym_version_prop->get_value()->as_string()
4135     : "";
4136 
4137   ini::simple_property_sptr sym_version_regex_prop =
4138     is_simple_property(section.find_property("symbol_version_regexp"));
4139   string symbol_version_regex_str = sym_version_regex_prop
4140     ? sym_version_regex_prop->get_value()->as_string()
4141      : "";
4142 
4143   ini::simple_property_sptr type_name_prop =
4144     is_simple_property(section.find_property("type_name"));
4145   string type_name_str = type_name_prop
4146     ? type_name_prop->get_value()->as_string()
4147     : "";
4148 
4149   ini::simple_property_sptr type_name_regex_prop =
4150     is_simple_property(section.find_property("type_name_regexp"));
4151   string type_name_regex_str = type_name_regex_prop
4152     ? type_name_regex_prop->get_value()->as_string()
4153      : "";
4154 
4155   result.reset(new variable_suppression(label_str,
4156 					name_str,
4157 					name_regex_str,
4158 					symbol_name,
4159 					symbol_name_regex_str,
4160 					symbol_version,
4161 					symbol_version_regex_str,
4162 					type_name_str,
4163 					type_name_regex_str));
4164 
4165   if ((drop_artifact_str == "yes" || drop_artifact_str == "true")
4166       && (!name_str.empty()
4167 	  || !name_regex_str.empty()
4168 	  || !name_not_regex_str.empty()
4169 	  || !symbol_name.empty()
4170 	  || !symbol_name_regex_str.empty()
4171 	  || !symbol_name_not_regex_str.empty()))
4172     result->set_drops_artifact_from_ir(true);
4173 
4174   if (!name_not_regex_str.empty())
4175     result->set_name_not_regex_str(name_not_regex_str);
4176 
4177   if (!symbol_name_not_regex_str.empty())
4178     result->set_symbol_name_not_regex_str(symbol_name_not_regex_str);
4179 
4180   if (!change_kind_str.empty())
4181     result->set_change_kind
4182       (variable_suppression::parse_change_kind(change_kind_str));
4183 
4184   if (!file_name_regex_str.empty())
4185     result->set_file_name_regex_str(file_name_regex_str);
4186 
4187   if (!file_name_not_regex_str.empty())
4188     result->set_file_name_not_regex_str(file_name_not_regex_str);
4189 
4190   if (!soname_regex_str.empty())
4191     result->set_soname_regex_str(soname_regex_str);
4192 
4193   if (!soname_not_regex_str.empty())
4194     result->set_soname_not_regex_str(soname_not_regex_str);
4195 
4196   return result;
4197 }
4198 
4199 // </variable_suppression stuff>
4200 
4201 // <file_suppression stuff>
4202 
4203 /// Constructor for the the @ref file_suppression type.
4204 ///
4205 /// @param label the label of the suppression directive.
4206 ///
4207 /// @param fname_regex_str the regular expression string that
4208 /// designates the file name that instances of @ref file_suppression
4209 /// should match.
4210 ///
4211 /// @param fname_not_regex_str the regular expression string that
4212 /// designates the file name that instances of @ref file_suppression
4213 /// shoult *NOT* match.  In other words, this file_suppression should
4214 /// be activated if its file name does not match the regular
4215 /// expression @p fname_not_regex_str.
file_suppression(const string & label,const string & fname_regex_str,const string & fname_not_regex_str)4216 file_suppression::file_suppression(const string& label,
4217 				   const string& fname_regex_str,
4218 				   const string& fname_not_regex_str)
4219   : suppression_base(label,
4220 		     fname_regex_str,
4221 		     fname_not_regex_str)
4222 {}
4223 
4224 /// Test if instances of this @ref file_suppression suppresses a
4225 /// certain instance of @ref diff.
4226 ///
4227 /// This function always returns false because, obviously, a
4228 /// file_suppression is meants to prevents Abigail tools from loading
4229 /// some files.  It is not meant to act on instance of @ref diff.
4230 /// @return false.
4231 bool
suppresses_diff(const diff *) const4232 file_suppression::suppresses_diff(const diff*) const
4233 {return false;}
4234 
4235 /// Test if a instances of this @ref file_suppression suppresses a
4236 /// given file.
4237 ///
4238 /// @param file_path the file path to test against.
4239 ///
4240 /// @return true iff this file_suppression matches the file path @p
4241 /// file_path.
4242 bool
suppresses_file(const string & file_path)4243 file_suppression::suppresses_file(const string& file_path)
4244 {
4245   if (file_path.empty())
4246     return false;
4247 
4248   string fname;
4249   tools_utils::base_name(file_path, fname);
4250 
4251   bool has_regexp = false;
4252 
4253   if (regex_t_sptr regexp = suppression_base::priv_->get_file_name_regex())
4254     {
4255       has_regexp = true;
4256       if (!regex::match(regexp, fname))
4257 	return false;
4258     }
4259 
4260   if (regex_t_sptr regexp = suppression_base::priv_->get_file_name_not_regex())
4261     {
4262       has_regexp = true;
4263       if (regex::match(regexp, fname))
4264 	return false;
4265     }
4266 
4267   if (!has_regexp)
4268     return false;
4269 
4270   return true;
4271 }
4272 
4273 /// Destructor of @ref file_suppression.
~file_suppression()4274 file_suppression::~file_suppression()
4275 {
4276 }
4277 
4278 /// Read a file suppression from an instance of ini::config::section
4279 /// and build a @ref type_suppression as a result.
4280 ///
4281 /// @param section the section (from an ini file) to read the file
4282 /// suppression from.
4283 ///
4284 /// @return file_suppression_sptr.
4285 static file_suppression_sptr
read_file_suppression(const ini::config::section & section)4286 read_file_suppression(const ini::config::section& section)
4287 {
4288   file_suppression_sptr result;
4289 
4290   if (section.get_name() != "suppress_file")
4291     return result;
4292 
4293   static const char *const sufficient_props[] = {
4294     "file_name_regexp",
4295     "file_name_not_regexp",
4296     "soname_regexp",
4297     "soname_not_regexp",
4298   };
4299   if (!check_sufficient_props(sufficient_props,
4300 			      sizeof(sufficient_props)/sizeof(char*),
4301 			      section))
4302     return result;
4303 
4304   ini::simple_property_sptr label_prop =
4305     is_simple_property(section.find_property("label"));
4306   string label_str = (label_prop
4307 		      ? label_prop->get_value()->as_string()
4308 		      : "");
4309 
4310   ini::simple_property_sptr file_name_regex_prop =
4311     is_simple_property(section.find_property("file_name_regexp"));
4312   string file_name_regex_str =
4313     file_name_regex_prop ? file_name_regex_prop->get_value()->as_string() : "";
4314 
4315  ini::simple_property_sptr file_name_not_regex_prop =
4316     is_simple_property(section.find_property("file_name_not_regexp"));
4317   string file_name_not_regex_str =
4318     file_name_not_regex_prop
4319     ? file_name_not_regex_prop->get_value()->as_string()
4320     : "";
4321 
4322   ini::simple_property_sptr soname_regex_prop =
4323     is_simple_property(section.find_property("soname_regexp"));
4324   string soname_regex_str =
4325     soname_regex_prop ? soname_regex_prop->get_value()->as_string() : "";
4326 
4327   ini::simple_property_sptr soname_not_regex_prop =
4328     is_simple_property(section.find_property("soname_not_regexp"));
4329   string soname_not_regex_str =
4330     soname_not_regex_prop
4331     ? soname_not_regex_prop->get_value()->as_string()
4332     : "";
4333 
4334   result.reset(new file_suppression(label_str,
4335 				    file_name_regex_str,
4336 				    file_name_not_regex_str));
4337 
4338   if (!soname_regex_str.empty())
4339     {
4340       result->set_soname_regex_str(soname_regex_str);
4341       result->set_drops_artifact_from_ir(true);
4342     }
4343 
4344   if (!soname_not_regex_str.empty())
4345     {
4346       result->set_soname_not_regex_str(soname_not_regex_str);
4347       result->set_drops_artifact_from_ir(true);
4348     }
4349 
4350   return result;
4351 }
4352 
4353 /// Test if a given suppression specification is a file suppression
4354 /// specification.
4355 ///
4356 /// @param s the instance of @ref suppression_base to test.
4357 ///
4358 /// @return the instance of @ref file_suppression that @p s points to,
4359 /// iff s is an instance of @ref file_suppression.  Otherwise, returns
4360 /// nil.
4361 file_suppression_sptr
is_file_suppression(const suppression_sptr s)4362 is_file_suppression(const suppression_sptr s)
4363 {return dynamic_pointer_cast<file_suppression>(s);}
4364 
4365 /// Test if a given file path is "suppressed" by at least one file
4366 /// suppression specification among a vector of suppression
4367 /// specifications.
4368 ///
4369 /// @param file_path the file path to test.
4370 ///
4371 /// @param sprs the vector of suppressions to use to test if one of
4372 /// them at lease matches the file path @p file_path.
4373 ///
4374 /// @return a pointer to the first instance of @ref file_suppression
4375 /// that matches @p file_path, or nil if no file suppression matches.
4376 file_suppression_sptr
file_is_suppressed(const string & file_path,const suppressions_type & sprs)4377 file_is_suppressed(const string& file_path,
4378 		   const suppressions_type& sprs)
4379 {
4380   for (suppressions_type::const_iterator i = sprs.begin(); i != sprs.end(); ++i)
4381     if (file_suppression_sptr s = is_file_suppression(*i))
4382       if (s->suppresses_file(file_path))
4383 	return s;
4384 
4385   return file_suppression_sptr();
4386 }
4387 
4388 /// Test if a given SONAME is matched by a given suppression
4389 /// specification.
4390 ///
4391 /// @param soname the SONAME to consider.
4392 ///
4393 /// @param suppr the suppression specification to consider.
4394 ///
4395 /// @return true iff a given SONAME is matched by a given suppression
4396 /// specification.
4397 bool
suppression_matches_soname(const string & soname,const suppression_base & suppr)4398 suppression_matches_soname(const string& soname,
4399 			   const suppression_base& suppr)
4400 {
4401   return suppr.priv_->matches_soname(soname);
4402 }
4403 
4404 /// Test if a given SONAME or file name is matched by a given
4405 /// suppression specification.
4406 ///
4407 /// @param soname the SONAME to consider.
4408 ///
4409 /// @param filename the file name to consider.
4410 ///
4411 /// @param suppr the suppression specification to consider.
4412 ///
4413 /// @return true iff either @p soname or @p filename is matched by the
4414 /// suppression specification @p suppr.
4415 bool
suppression_matches_soname_or_filename(const string & soname,const string & filename,const suppression_base & suppr)4416 suppression_matches_soname_or_filename(const string& soname,
4417 				       const string& filename,
4418 				       const suppression_base& suppr)
4419 {
4420   return (suppression_matches_soname(soname, suppr)
4421 	 || suppr.priv_->matches_binary_name(filename));
4422 }
4423 
4424 /// @return the name of the artificial private type suppression
4425 /// specification that is auto-generated by libabigail to suppress
4426 /// change reports about types that are not defined in public headers.
4427 const char*
get_private_types_suppr_spec_label()4428 get_private_types_suppr_spec_label()
4429 {
4430   static const char *PRIVATE_TYPES_SUPPR_SPEC_NAME =
4431     "Artificial private types suppression specification";
4432 
4433   return PRIVATE_TYPES_SUPPR_SPEC_NAME;
4434 }
4435 
4436 /// Test if a type suppression specification represents a private type
4437 /// suppression automatically generated by libabigail from the user
4438 /// telling us where public headers are.
4439 ///
4440 /// @param s the suppression specification we are looking at.
4441 ///
4442 /// @return true iff @p s is a private type suppr spec.
4443 bool
is_private_type_suppr_spec(const type_suppression & s)4444 is_private_type_suppr_spec(const type_suppression& s)
4445 {return s.get_label() == get_private_types_suppr_spec_label();}
4446 
4447 /// Test if a type suppression specification represents a private type
4448 /// suppression automatically generated by libabigail from the user
4449 /// telling us where public headers are.
4450 ///
4451 /// @param s the suppression specification we are looking at.
4452 ///
4453 /// @return true iff @p s is a private type suppr spec.
4454 bool
is_private_type_suppr_spec(const suppression_sptr & s)4455 is_private_type_suppr_spec(const suppression_sptr& s)
4456 {
4457   type_suppression_sptr type_suppr = is_type_suppression(s);
4458   return (type_suppr
4459 	  && type_suppr->get_label() == get_private_types_suppr_spec_label());
4460 }
4461 
4462 // </file_suppression stuff>
4463 }// end namespace suppr
4464 } // end namespace abigail
4465