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