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