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