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