1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2016-2020 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 #ifndef __ABG_SUPPRESSION_H__
9 #define __ABG_SUPPRESSION_H__
10 
11 #include <unordered_set>
12 
13 #include "abg-ini.h"
14 #include "abg-comparison.h"
15 
16 namespace abigail
17 {
18 
19 /// @brief an engine to suppress the parts of the result of comparing
20 /// two sets of ABI artifacts.
21 ///
22 /// The user specifies the kind of changes between ABI artefact she
23 /// wants to see suppressed.  That suppression specification is done
24 /// in an INI format.
25 ///
26 /// That INI file is parsed and represented internally using the types
27 /// that are defined in this namespace.
28 namespace suppr
29 {
30 
31 using namespace abigail::comparison;
32 using std::unordered_set;
33 
34 /// Base type of the suppression specifications types.
35 ///
36 /// This abstracts a suppression specification.  It's a way to specify
37 /// how to drop reports about a particular diff node on the floor, if
38 /// it matches the supppression specification.
39 class suppression_base
40 {
41   class priv;
42   typedef shared_ptr<priv> priv_sptr;
43 
44   // Forbid default constructor
45   suppression_base();
46 
47 public:
48   priv_sptr priv_;
49 
50   suppression_base(const string& label);
51 
52   suppression_base(const string& label,
53 		   const string& file_name_regex_str,
54 		   const string& file_name_not_regex_str);
55 
56   bool
57   get_drops_artifact_from_ir() const;
58 
59   void
60   set_drops_artifact_from_ir(bool);
61 
62   bool
63   get_is_artificial() const;
64 
65   void
66   set_is_artificial(bool);
67 
68   const string
69   get_label() const;
70 
71   void
72   set_label(const string&);
73 
74   void
75   set_file_name_regex_str(const string& regexp);
76 
77   const string&
78   get_file_name_regex_str() const;
79 
80   void
81   set_file_name_not_regex_str(const string& regexp);
82 
83   const string&
84   get_file_name_not_regex_str() const;
85 
86   bool
87   has_file_name_related_property() const;
88 
89   void
90   set_soname_regex_str(const string& regexp);
91 
92   const string&
93   get_soname_regex_str() const;
94 
95   void
96   set_soname_not_regex_str(const string& regexp);
97 
98   const string&
99   get_soname_not_regex_str() const;
100 
101   bool
102   has_soname_related_property() const;
103 
104   virtual bool
105   suppresses_diff(const diff*) const = 0;
106 
107   virtual ~suppression_base();
108 
109   friend bool
110   suppression_matches_soname(const string& soname,
111 			     const suppression_base& suppr);
112 
113   friend bool
114   suppression_matches_soname_or_filename(const string& soname,
115 					 const string& filename,
116 					 const suppression_base& suppr);
117 }; // end class suppression_base
118 
119 void
120 read_suppressions(std::istream& input,
121 		  suppressions_type& suppressions);
122 
123 void
124 read_suppressions(const string& file_path,
125 		  suppressions_type& suppressions);
126 
127 class type_suppression;
128 
129 /// Convenience typedef for a shared pointer to type_suppression.
130 typedef shared_ptr<type_suppression> type_suppression_sptr;
131 
132 /// Convenience typedef for vector of @ref type_suppression_sptr.
133 typedef vector<type_suppression_sptr> type_suppressions_type;
134 
135 /// Abstraction of a type suppression specification.
136 ///
137 /// Specifies under which condition reports about a type diff node
138 /// should be dropped on the floor.
139 class type_suppression : public suppression_base
140 {
141   class priv;
142   typedef shared_ptr<priv> priv_sptr;
143 
144   // Forbid this;
145   type_suppression();
146 
147 public:
148 
149   priv_sptr priv_;
150 
151   /// The kind of the type the current type suppression is supposed to
152   /// be about.
153   enum type_kind
154   {
155     UNKNOWN_TYPE_KIND,
156     CLASS_TYPE_KIND,
157     STRUCT_TYPE_KIND,
158     UNION_TYPE_KIND,
159     ENUM_TYPE_KIND,
160     ARRAY_TYPE_KIND,
161     TYPEDEF_TYPE_KIND,
162     BUILTIN_TYPE_KIND
163   }; // end enum type_kind
164 
165   /// The different ways through which the type diff has been reached.
166   enum reach_kind
167   {
168     /// The type diff has been reached (from a function or variable
169     /// change) directly.
170     DIRECT_REACH_KIND = 0,
171 
172     /// The type diff has been reached (from a function or variable
173     /// change) through a pointer.
174     POINTER_REACH_KIND,
175 
176     /// The type diff has been reached (from a function or variable
177     /// change) through a reference; you know, like a c++ reference..
178     REFERENCE_REACH_KIND,
179 
180     /// The type diff has been reached (from a function or variable
181     /// change) through either a reference or a pointer.
182     REFERENCE_OR_POINTER_REACH_KIND
183   }; // end enum reach_kind
184 
185   class insertion_range;
186   /// A convenience typedef for a shared pointer to @ref
187   /// insertion_range.
188   typedef shared_ptr<insertion_range> insertion_range_sptr;
189   /// A convenience typedef for a vector of @ref insertion_range_sptr.
190   typedef vector<insertion_range_sptr> insertion_ranges;
191 
192   type_suppression(const string& label,
193 		   const string& type_name_regexp,
194 		   const string& type_name);
195 
196   virtual ~type_suppression();
197 
198   void
199   set_type_name_regex_str(const string& name_regex_str);
200 
201   const string&
202   get_type_name_regex_str() const;
203 
204   void
205   set_type_name_not_regex_str(const string& name_regex_str);
206 
207   const string&
208   get_type_name_not_regex_str() const;
209 
210   void
211   set_type_name(const string& name);
212 
213   const string&
214   get_type_name() const;
215 
216   bool
217   get_consider_type_kind() const;
218 
219   void
220   set_consider_type_kind(bool f);
221 
222   void
223   set_type_kind(type_kind k);
224 
225   type_kind
226   get_type_kind() const;
227 
228   bool
229   get_consider_reach_kind() const;
230 
231   void
232   set_consider_reach_kind(bool f);
233 
234   reach_kind
235   get_reach_kind() const;
236 
237   void
238   set_reach_kind(reach_kind k);
239 
240   void
241   set_data_member_insertion_ranges(const insertion_ranges& r);
242 
243   const insertion_ranges&
244   get_data_member_insertion_ranges() const;
245 
246   insertion_ranges&
247   get_data_member_insertion_ranges();
248 
249   const unordered_set<string>&
250   get_source_locations_to_keep() const;
251 
252   unordered_set<string>&
253   get_source_locations_to_keep();
254 
255   void
256   set_source_locations_to_keep(const unordered_set<string>&);
257 
258   const string&
259   get_source_location_to_keep_regex_str() const;
260 
261   void
262   set_source_location_to_keep_regex_str(const string&);
263 
264   const vector<string>&
265   get_changed_enumerator_names() const;
266 
267   void
268   set_changed_enumerator_names(const vector<string>&);
269 
270   virtual bool
271   suppresses_diff(const diff* diff) const;
272 
273   bool
274   suppresses_type(const type_base_sptr& type,
275 		  const diff_context_sptr& ctxt) const;
276 
277   bool
278   suppresses_type(const type_base_sptr& type) const;
279 
280   bool
281   suppresses_type(const type_base_sptr& type,
282 		  const scope_decl* type_scope) const;
283 }; // end type_suppression
284 
285 type_suppression_sptr
286 is_type_suppression(const suppression_sptr);
287 
288 /// The abstraction of a range of offsets in which a member of a type
289 /// might get inserted.
290 class type_suppression::insertion_range
291 {
292 public:
293 
294   class boundary;
295   class integer_boundary;
296   class fn_call_expr_boundary;
297 
298   /// Convenience typedef for a shared_ptr to @ref boundary
299   typedef shared_ptr<boundary> boundary_sptr;
300 
301   /// Convenience typedef for a shared_ptr to a @ref integer_boundary
302   typedef shared_ptr<integer_boundary> integer_boundary_sptr;
303 
304   /// Convenience typedef for a shared_ptr to a @ref
305   /// fn_call_expr_boundary
306   typedef shared_ptr<fn_call_expr_boundary> fn_call_expr_boundary_sptr;
307 
308 private:
309   struct priv;
310   typedef shared_ptr<priv> priv_sptr;
311 
312   priv_sptr priv_;
313 
314 public:
315   insertion_range();
316 
317   insertion_range(boundary_sptr begin, boundary_sptr end);
318 
319   boundary_sptr
320   begin() const;
321 
322  boundary_sptr
323   end() const;
324 
325   static insertion_range::integer_boundary_sptr
326   create_integer_boundary(int value);
327 
328   static insertion_range::fn_call_expr_boundary_sptr
329   create_fn_call_expr_boundary(ini::function_call_expr_sptr);
330 
331   static insertion_range::fn_call_expr_boundary_sptr
332   create_fn_call_expr_boundary(const string&);
333 
334   static bool
335   eval_boundary(boundary_sptr	boundary,
336 		class_decl_sptr context,
337 		ssize_t&	value);
338 }; // end class insertion_range
339 
340 type_suppression::insertion_range::integer_boundary_sptr
341 is_integer_boundary(type_suppression::insertion_range::boundary_sptr);
342 
343 type_suppression::insertion_range::fn_call_expr_boundary_sptr
344 is_fn_call_expr_boundary(type_suppression::insertion_range::boundary_sptr);
345 
346 /// The abstraction of the boundary of an @ref insertion_range, in the
347 /// context of a @ref type_suppression
348 class type_suppression::insertion_range::boundary
349 {
350   struct priv;
351   typedef shared_ptr<priv> priv_sptr;
352 
353   priv_sptr priv_;
354 
355 public:
356   boundary();
357   virtual ~boundary();
358 };// end class type_suppression::insertion_range::boundary
359 
360 /// An @ref insertion_range boundary that is expressed as an integer
361 /// value.  That integer value is usually a bit offset.
362 class type_suppression::insertion_range::integer_boundary
363   : public type_suppression::insertion_range::boundary
364 {
365   struct priv;
366   typedef shared_ptr<priv> priv_sptr;
367 
368   priv_sptr priv_;
369 
370   integer_boundary();
371 
372 public:
373   integer_boundary(int value);
374   int as_integer() const;
375   operator int() const;
376   ~integer_boundary();
377 }; //end class type_suppression::insertion_range::integer_boundary
378 
379 /// An @ref insertion_range boundary that is expressed as function
380 /// call expression.  The (integer) value of that expression is
381 /// usually a bit offset.
382 class type_suppression::insertion_range::fn_call_expr_boundary
383   : public type_suppression::insertion_range::boundary
384 {
385   struct priv;
386   typedef shared_ptr<priv> priv_sptr;
387 
388   priv_sptr priv_;
389 
390   fn_call_expr_boundary();
391 
392 public:
393   fn_call_expr_boundary(ini::function_call_expr_sptr expr);
394   ini::function_call_expr_sptr as_function_call_expr() const;
395   operator ini::function_call_expr_sptr () const;
396   ~fn_call_expr_boundary();
397 }; //end class type_suppression::insertion_range::fn_call_expr_boundary
398 
399 class function_suppression;
400 
401 /// Convenience typedef for a shared pointer to function_suppression.
402 typedef shared_ptr<function_suppression> function_suppression_sptr;
403 
404 /// Convenience typedef for a vector of @ref function_suppression_sptr.
405 typedef vector<function_suppression_sptr> function_suppressions_type;
406 
407 /// Abstraction of a function suppression specification.
408 ///
409 /// Specifies under which condition reports about a @ref
410 /// function_decl_diff diff node should be dropped on the floor for
411 /// the purpose of reporting.
412 class function_suppression : public suppression_base
413 {
414   struct priv;
415   typedef shared_ptr<priv> priv_sptr;
416 
417 public:
418 
419   priv_sptr priv_;
420   class parameter_spec;
421 
422   /// Convenience typedef for shared_ptr of @ref parameter_spec.
423   typedef shared_ptr<parameter_spec> parameter_spec_sptr;
424 
425   /// Convenience typedef for vector of @ref parameter_spec_sptr.
426   typedef vector<parameter_spec_sptr> parameter_specs_type;
427 
428   /// The kind of change the current function suppression should apply
429   /// to.
430   enum change_kind
431   {
432     UNDEFINED_CHANGE_KIND,
433     /// A change in a sub-type of the function.
434     FUNCTION_SUBTYPE_CHANGE_KIND = 1,
435     /// The function was added to the second subject of the diff.
436     ADDED_FUNCTION_CHANGE_KIND = 1 << 1,
437     /// The function was deleted from the second subject of the diff.
438     DELETED_FUNCTION_CHANGE_KIND = 1 << 2,
439     /// This represents all the changes possibly described by this
440     /// enum.  It's a logical 'OR' of all the change enumerators
441     /// above.
442     ALL_CHANGE_KIND = (FUNCTION_SUBTYPE_CHANGE_KIND
443 		       | ADDED_FUNCTION_CHANGE_KIND
444 		       | DELETED_FUNCTION_CHANGE_KIND)
445   };
446 
447   function_suppression();
448 
449   function_suppression(const string&		label,
450 		       const string&		name,
451 		       const string&		name_regex,
452 		       const string&		return_type_name,
453 		       const string&		return_type_regex,
454 		       parameter_specs_type&	parm_specs,
455 		       const string&		symbol_name,
456 		       const string&		symbol_name_regex,
457 		       const string&		symbol_version,
458 		       const string&		symbol_version_regex_str);
459 
460   virtual ~function_suppression();
461 
462   static change_kind
463   parse_change_kind(const string&);
464 
465   change_kind
466   get_change_kind() const;
467 
468   void
469   set_change_kind(change_kind k);
470 
471   const string&
472   get_name() const;
473 
474   void
475   set_name(const string&);
476 
477   const string&
478   get_name_regex_str() const;
479 
480   void
481   set_name_regex_str(const string&);
482 
483   const string&
484   get_name_not_regex_str() const;
485 
486   void
487   set_name_not_regex_str(const string&);
488 
489   const string&
490   get_return_type_name() const;
491 
492   void
493   set_return_type_name(const string&);
494 
495   const string&
496   get_return_type_regex_str() const;
497 
498   void
499   set_return_type_regex_str(const string& r);
500 
501   const parameter_specs_type&
502   get_parameter_specs() const;
503 
504   void
505   set_parameter_specs(parameter_specs_type&);
506 
507   void
508   append_parameter_specs(const parameter_spec_sptr);
509 
510   const string&
511   get_symbol_name() const;
512 
513   void
514   set_symbol_name(const string& n);
515 
516   const string&
517   get_symbol_name_regex_str() const;
518 
519   void
520   set_symbol_name_regex_str(const string&);
521 
522   const string&
523   get_symbol_name_not_regex_str() const;
524 
525   void
526   set_symbol_name_not_regex_str(const string&);
527 
528   const string&
529   get_symbol_version() const;
530 
531   void
532   set_symbol_version(const string&);
533 
534   const string&
535   get_symbol_version_regex_str() const;
536 
537   void
538   set_symbol_version_regex_str(const string&);
539 
540   bool
541   get_allow_other_aliases() const;
542 
543   void
544   set_allow_other_aliases(bool f);
545 
546   virtual bool
547   suppresses_diff(const diff* diff) const;
548 
549   bool
550   suppresses_function(const function_decl* fn,
551 		      change_kind k,
552 		      const diff_context_sptr ctxt) const;
553 
554   bool
555   suppresses_function(const function_decl_sptr fn,
556 		      change_kind k,
557 		      const diff_context_sptr ctxt) const;
558 
559   bool
560   suppresses_function_symbol(const elf_symbol* sym,
561 			     change_kind k,
562 			     const diff_context_sptr ctxt);
563 
564   bool
565   suppresses_function_symbol(const elf_symbol_sptr sym,
566 			     change_kind k,
567 			     const diff_context_sptr ctxt);
568 }; // end class function_suppression.
569 
570 function_suppression_sptr
571 is_function_suppression(const suppression_sptr);
572 
573 function_suppression::change_kind
574 operator&(function_suppression::change_kind l,
575 	  function_suppression::change_kind r);
576 
577 function_suppression::change_kind
578 operator|(function_suppression::change_kind l,
579 	  function_suppression::change_kind r);
580 
581 /// Abstraction of the specification of a function parameter in a
582 /// function suppression specification.
583 class function_suppression::parameter_spec
584 {
585   class priv;
586   typedef shared_ptr<priv> priv_sptr;
587 
588   friend class function_suppression;
589 
590   priv_sptr priv_;
591 
592   // Forbid this.
593   parameter_spec();
594 
595 public:
596   parameter_spec(size_t index,
597 		 const string& type_name,
598 		 const string& type_name_regex);
599 
600   size_t
601   get_index() const;
602 
603   void
604   set_index(size_t);
605 
606   const string&
607   get_parameter_type_name() const;
608 
609   void
610   set_parameter_type_name(const string&);
611 
612   const string&
613   get_parameter_type_name_regex_str() const;
614 
615   void
616   set_parameter_type_name_regex_str(const string&);
617 };// end class function_suppression::parameter_spec
618 
619 class variable_suppression;
620 
621 /// A convenience typedef for a shared pointer to @ref
622 /// variable_suppression.
623 typedef shared_ptr<variable_suppression> variable_suppression_sptr;
624 
625 /// A convenience typedef for a vector of @ref
626 /// variable_suppression_sptr.
627 typedef vector<variable_suppression_sptr> variable_suppressions_type;
628 
629 /// The abstraction of a variable suppression specification.
630 ///
631 /// It specifies under which condition reports about a @ref var_diff
632 /// diff node should be dropped on the floor for the purpose of
633 /// reporting.
634 class variable_suppression : public suppression_base
635 {
636 public:
637 
638   /// The kind of change the current variable suppression should apply
639   /// to.
640   enum change_kind
641   {
642     UNDEFINED_CHANGE_KIND,
643     /// A change in a sub-type of the variable.
644     VARIABLE_SUBTYPE_CHANGE_KIND = 1,
645     /// The variable was added to the second second subject of the
646     /// diff.
647     ADDED_VARIABLE_CHANGE_KIND = 1 << 1,
648     /// The variable was deleted from the second subject of the diff.
649     DELETED_VARIABLE_CHANGE_KIND = 1 << 2,
650     /// This represents all the changes possibly described by this
651     /// enum.  It's a logical 'OR' of all the change enumerators
652     /// above.
653     ALL_CHANGE_KIND = (VARIABLE_SUBTYPE_CHANGE_KIND
654 		       | ADDED_VARIABLE_CHANGE_KIND
655 		       | DELETED_VARIABLE_CHANGE_KIND)
656   };
657 
658 private:
659   struct priv;
660   typedef shared_ptr<priv> priv_sptr;
661 
662 public:
663 
664   priv_sptr priv_;
665 
666   variable_suppression(const string& label = "",
667 		       const string& name = "",
668 		       const string& name_regex_str = "",
669 		       const string& symbol_name = "",
670 		       const string& symbol_name_regex_str = "",
671 		       const string& symbol_version = "",
672 		       const string& symbol_version_regex_str = "",
673 		       const string& type_name = "",
674 		       const string& type_name_regex_str = "");
675 
676   virtual ~variable_suppression();
677 
678   static change_kind
679   parse_change_kind(const string&);
680 
681   change_kind
682   get_change_kind() const;
683 
684   void
685   set_change_kind(change_kind k);
686 
687   const string&
688   get_name() const;
689 
690   void
691   set_name(const string&);
692 
693   const string&
694   get_name_regex_str() const;
695 
696   void
697   set_name_regex_str(const string&);
698 
699   const string&
700   get_name_not_regex_str() const;
701 
702   void
703   set_name_not_regex_str(const string&);
704 
705   const string&
706   get_symbol_name() const;
707 
708   void
709   set_symbol_name(const string&);
710 
711   const string&
712   get_symbol_name_regex_str() const;
713 
714   void
715   set_symbol_name_regex_str(const string&);
716 
717   const string&
718   get_symbol_name_not_regex_str() const;
719 
720   void
721   set_symbol_name_not_regex_str(const string&);
722 
723   const string&
724   get_symbol_version() const;
725 
726   void
727   set_symbol_version(const string&);
728 
729   const string&
730   get_symbol_version_regex_str() const;
731 
732   void
733   set_symbol_version_regex_str(const string&);
734 
735   const string&
736   get_type_name() const;
737 
738   void
739   set_type_name(const string&);
740 
741   const string&
742   get_type_name_regex_str() const;
743 
744   void
745   set_type_name_regex_str(const string&);
746 
747   bool
748   suppresses_diff(const diff* d) const;
749 
750   bool
751   suppresses_variable(const var_decl* var,
752 		      change_kind k,
753 		      const diff_context_sptr cxt) const;
754 
755   bool
756   suppresses_variable(const var_decl_sptr var,
757 		      change_kind k,
758 		      const diff_context_sptr cxt) const;
759 
760   bool
761   suppresses_variable_symbol(const elf_symbol* sym,
762 			     change_kind k,
763 			     const diff_context_sptr cxt) const;
764 
765   bool
766   suppresses_variable_symbol(const elf_symbol_sptr fn,
767 			     change_kind k,
768 			     const diff_context_sptr cxt) const;
769 }; // end class variable_suppression
770 
771 variable_suppression_sptr
772 is_variable_suppression(const suppression_sptr);
773 
774 variable_suppression::change_kind
775 operator&(variable_suppression::change_kind l,
776 	  variable_suppression::change_kind r);
777 
778 variable_suppression::change_kind
779 operator|(variable_suppression::change_kind l,
780 	  variable_suppression::change_kind r);
781 
782 class file_suppression;
783 
784 /// A convenience typedef for a shared_ptr to @ref file_suppression
785 typedef shared_ptr<file_suppression> file_suppression_sptr;
786 
787 /// Abstraction of a suppression specification to avoid loading a
788 /// file.
789 ///
790 /// This can be used by a tool that loads (binary) files, to know
791 /// which file it has to avoid loading.
792 class file_suppression: public suppression_base
793 {
794   class priv;
795   typedef shared_ptr<priv> priv_sptr;
796 
797   priv_sptr priv_;
798 
799   // Forbid this
800   file_suppression();
801 
802 public:
803 
804   file_suppression(const string& label,
805 		   const string& file_name_regex,
806 		   const string& file_name_not_regex);
807 
808   virtual bool
809   suppresses_diff(const diff* diff) const;
810 
811   bool
812   suppresses_file(const string& file_path);
813 
814   virtual ~file_suppression();
815 }; // end file_suppression
816 
817 file_suppression_sptr
818 is_file_suppression(const suppression_sptr);
819 
820 file_suppression_sptr
821 file_is_suppressed(const string& file_path,
822 		   const suppressions_type& suppressions);
823 
824 bool
825 suppression_matches_soname(const string& soname,
826 			   const suppression_base& suppr);
827 
828 bool
829 suppression_matches_soname_or_filename(const string& soname,
830 				       const string& filename,
831 				       const suppression_base& suppr);
832 
833 const char*
834 get_private_types_suppr_spec_label();
835 
836 bool
837 is_private_type_suppr_spec(const type_suppression&);
838 
839 bool
840 is_private_type_suppr_spec(const suppression_sptr& s);
841 } // end namespace suppr
842 
843 } // end namespace abigail
844 
845 #endif //__ABG_SUPPRESSION_H__
846