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