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