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 private implementation of the suppression engine 11 /// of libabigail. 12 13 #ifndef __ABG_SUPPRESSION_PRIV_H__ 14 #define __ABG_SUPPRESSION_PRIV_H__ 15 16 #include "abg-fwd.h" 17 #include "abg-regex.h" 18 #include "abg-sptr-utils.h" 19 #include "abg-suppression.h" 20 21 namespace abigail 22 { 23 24 namespace suppr 25 { 26 27 // <suppression_base stuff> 28 29 /// The private data of @ref suppression_base. 30 class suppression_base::priv 31 { 32 bool is_artificial_; 33 bool drops_artifact_; 34 string label_; 35 string file_name_regex_str_; 36 mutable regex::regex_t_sptr file_name_regex_; 37 string file_name_not_regex_str_; 38 mutable regex::regex_t_sptr file_name_not_regex_; 39 string soname_regex_str_; 40 mutable regex::regex_t_sptr soname_regex_; 41 string soname_not_regex_str_; 42 mutable regex::regex_t_sptr soname_not_regex_; 43 44 public: priv()45 priv() 46 : is_artificial_(), 47 drops_artifact_() 48 {} 49 priv(const string & label)50 priv(const string& label) 51 : is_artificial_(), 52 drops_artifact_(), 53 label_(label) 54 {} 55 priv(const string & label,const string & file_name_regex_str,const string & file_name_not_regex_str)56 priv(const string& label, 57 const string& file_name_regex_str, 58 const string& file_name_not_regex_str) 59 : is_artificial_(), 60 drops_artifact_(), 61 label_(label), 62 file_name_regex_str_(file_name_regex_str), 63 file_name_not_regex_str_(file_name_not_regex_str) 64 {} 65 66 friend class suppression_base; 67 68 /// Get the regular expression object associated to the 'file_name_regex' 69 /// property of @ref suppression_base. 70 /// 71 /// If the regular expression object is not created, this method 72 /// creates it and returns it. 73 /// 74 /// If the 'file_name_regex' property of @ref suppression_base is 75 /// empty then this method returns nil. 76 const regex::regex_t_sptr& get_file_name_regex()77 get_file_name_regex() const 78 { 79 if (!file_name_regex_ && !file_name_regex_str_.empty()) 80 file_name_regex_ = regex::compile(file_name_regex_str_); 81 return file_name_regex_; 82 } 83 84 /// Get the regular expression object associated to the 85 /// 'file_name_not_regex' property of @ref suppression_base. 86 /// 87 /// If the regular expression object is not created, this method 88 /// creates it and returns it. 89 /// 90 /// If the 'file_name_not_regex' property of @ref suppression_base 91 /// is empty then this method returns nil. 92 const regex::regex_t_sptr& get_file_name_not_regex()93 get_file_name_not_regex() const 94 { 95 if (!file_name_not_regex_ && !file_name_not_regex_str_.empty()) 96 file_name_not_regex_ = regex::compile(file_name_not_regex_str_); 97 return file_name_not_regex_; 98 } 99 100 /// Get the regular expression object associated to the 101 /// 'soname_regex' property of @ref suppression_base. 102 /// 103 /// If the regular expression object is not created, this method 104 /// creates it and returns it. 105 /// 106 /// If the 'soname_regex' property of @ref suppression_base is empty 107 /// then this method returns nil. 108 const regex::regex_t_sptr& get_soname_regex()109 get_soname_regex() const 110 { 111 if (!soname_regex_ && !soname_regex_str_.empty()) 112 soname_regex_ = regex::compile(soname_regex_str_); 113 return soname_regex_; 114 } 115 116 /// Get the regular expression object associated to the 117 /// 'soname_not_regex' property of @ref suppression_base. 118 /// 119 /// If the regular expression object is not created, this method 120 /// creates it and returns it. 121 /// 122 /// If the 'soname_not_regex' property of @ref suppression_base is 123 /// empty then this method returns nil. 124 const regex::regex_t_sptr& get_soname_not_regex()125 get_soname_not_regex() const 126 { 127 if (!soname_not_regex_ && !soname_not_regex_str_.empty()) 128 soname_not_regex_ = regex::compile(soname_not_regex_str_); 129 return soname_not_regex_; 130 } 131 132 /// Test if the current suppression matches a given SONAME. 133 /// 134 /// @param soname the SONAME to consider. 135 /// 136 /// @return true iff the suppression matches the SONAME denoted by 137 /// @p soname. 138 /// 139 /// Note that if the suppression contains no property that is 140 /// related to SONAMEs, the function returns false. 141 bool matches_soname(const string & soname)142 matches_soname(const string& soname) const 143 { 144 bool has_regexp = false; 145 if (regex::regex_t_sptr regexp = get_soname_regex()) 146 { 147 has_regexp = true; 148 if (!regex::match(regexp, soname)) 149 return false; 150 } 151 152 if (regex::regex_t_sptr regexp = get_soname_not_regex()) 153 { 154 has_regexp = true; 155 if (regex::match(regexp, soname)) 156 return false; 157 } 158 159 if (!has_regexp) 160 return false; 161 162 return true; 163 } 164 165 /// Test if the current suppression matches the full file path to a 166 /// given binary. 167 /// 168 /// @param binary_name the full path to the binary. 169 /// 170 /// @return true iff the suppression matches the path denoted by @p 171 /// binary_name. 172 /// 173 /// Note that if the suppression contains no property that is 174 /// related to file name, the function returns false. 175 bool matches_binary_name(const string & binary_name)176 matches_binary_name(const string& binary_name) const 177 { 178 bool has_regexp = false; 179 180 if (regex::regex_t_sptr regexp = get_file_name_regex()) 181 { 182 has_regexp = true; 183 if (!regex::match(regexp, binary_name)) 184 return false; 185 } 186 187 if (regex::regex_t_sptr regexp = get_file_name_not_regex()) 188 { 189 has_regexp = true; 190 if (regex::match(regexp, binary_name)) 191 return false; 192 } 193 194 if (!has_regexp) 195 return false; 196 197 return true; 198 } 199 200 }; // end clas suppression_base::priv 201 202 // </suppression_base stuff> 203 204 // <function_suppression stuff> 205 206 class function_suppression::parameter_spec::priv 207 { 208 friend class function_suppression::parameter_spec; 209 friend class function_suppression; 210 211 size_t index_; 212 string type_name_; 213 string type_name_regex_str_; 214 mutable regex::regex_t_sptr type_name_regex_; 215 priv()216 priv() 217 : index_() 218 {} 219 priv(size_t i,const string & tn)220 priv(size_t i, const string& tn) 221 : index_(i), type_name_(tn) 222 {} 223 priv(size_t i,const string & tn,const string & tn_regex)224 priv(size_t i, const string& tn, const string& tn_regex) 225 : index_(i), type_name_(tn), type_name_regex_str_(tn_regex) 226 {} 227 228 const regex::regex_t_sptr get_type_name_regex()229 get_type_name_regex() const 230 { 231 if (!type_name_regex_ && !type_name_regex_str_.empty()) 232 type_name_regex_ = regex::compile(type_name_regex_str_); 233 return type_name_regex_; 234 } 235 }; // end class function_suppression::parameter_spec::priv 236 237 238 /// The type of the private data of the @ref function_suppression 239 /// type. 240 struct function_suppression::priv 241 { 242 friend class function_suppression; 243 244 change_kind change_kind_; 245 string name_; 246 string name_regex_str_; 247 mutable regex::regex_t_sptr name_regex_; 248 string name_not_regex_str_; 249 mutable regex::regex_t_sptr name_not_regex_; 250 string return_type_name_; 251 string return_type_regex_str_; 252 mutable regex::regex_t_sptr return_type_regex_; 253 parameter_specs_type parm_specs_; 254 string symbol_name_; 255 string symbol_name_regex_str_; 256 mutable regex::regex_t_sptr symbol_name_regex_; 257 string symbol_name_not_regex_str_; 258 mutable regex::regex_t_sptr symbol_name_not_regex_; 259 string symbol_version_; 260 string symbol_version_regex_str_; 261 mutable regex::regex_t_sptr symbol_version_regex_; 262 bool allow_other_aliases_; 263 privpriv264 priv(): 265 change_kind_(ALL_CHANGE_KIND), 266 allow_other_aliases_(true) 267 {} 268 privpriv269 priv(const string& name, 270 const string& name_regex_str, 271 const string& return_type_name, 272 const string& return_type_regex_str, 273 const parameter_specs_type& parm_specs, 274 const string& symbol_name, 275 const string& symbol_name_regex_str, 276 const string& symbol_version, 277 const string& symbol_version_regex_str) 278 : change_kind_(ALL_CHANGE_KIND), 279 name_(name), 280 name_regex_str_(name_regex_str), 281 return_type_name_(return_type_name), 282 return_type_regex_str_(return_type_regex_str), 283 parm_specs_(parm_specs), 284 symbol_name_(symbol_name), 285 symbol_name_regex_str_(symbol_name_regex_str), 286 symbol_version_(symbol_version), 287 symbol_version_regex_str_(symbol_version_regex_str), 288 allow_other_aliases_(true) 289 {} 290 291 292 /// Getter for a pointer to a regular expression object built from 293 /// the regular expression string 294 /// function_suppression::priv::name_regex_str_. 295 /// 296 /// If that string is empty, then an empty regular expression object 297 /// pointer is returned. 298 /// 299 /// @return a pointer to the regular expression object of 300 /// function_suppression::priv::name_regex_str_.. 301 const regex::regex_t_sptr get_name_regexpriv302 get_name_regex() const 303 { 304 if (!name_regex_ && !name_regex_str_.empty()) 305 name_regex_ = regex::compile(name_regex_str_); 306 return name_regex_; 307 } 308 309 /// Getter for a pointer to a regular expression object built from 310 /// the regular expression string 311 /// function_suppression::priv::name_not_regex_str_. 312 /// 313 /// If that string is empty, then an empty regular expression object 314 /// pointer is returned. 315 /// 316 /// @return a pointer to the regular expression object of 317 /// function_suppression::priv::name_not_regex_str_.. 318 const regex::regex_t_sptr get_name_not_regexpriv319 get_name_not_regex() const 320 { 321 if (!name_not_regex_ && !name_not_regex_str_.empty()) 322 name_not_regex_ = regex::compile(name_not_regex_str_); 323 return name_not_regex_; 324 } 325 326 /// Getter for a pointer to a regular expression object built from 327 /// the regular expression string 328 /// function_suppression::priv::return_type_regex_str_. 329 /// 330 /// If that string is empty, then an empty regular expression object 331 /// pointer is returned. 332 /// 333 /// @return a pointer to the regular expression object of 334 /// function_suppression::priv::return_type_regex_str_. 335 const regex::regex_t_sptr get_return_type_regexpriv336 get_return_type_regex() const 337 { 338 if (!return_type_regex_ && !return_type_regex_str_.empty()) 339 return_type_regex_ = regex::compile(return_type_regex_str_); 340 return return_type_regex_; 341 } 342 343 /// Getter for a pointer to a regular expression object built from 344 /// the regular expression string 345 /// function_suppression::priv::symbol_name_regex_str_. 346 /// 347 /// If that string is empty, then an empty regular expression object 348 /// pointer is returned. 349 /// 350 /// @return a pointer to the regular expression object of 351 /// function_suppression::priv::symbol_name_regex_str_. 352 const regex::regex_t_sptr get_symbol_name_regexpriv353 get_symbol_name_regex() const 354 { 355 if (!symbol_name_regex_ && !symbol_name_regex_str_.empty()) 356 symbol_name_regex_ = regex::compile(symbol_name_regex_str_); 357 return symbol_name_regex_; 358 } 359 360 /// Getter for a pointer to a regular expression object built from 361 /// the regular expression string 362 /// function_suppression::priv::symbol_name_not_regex_str_. 363 /// 364 /// If that string is empty, then an empty regular expression object 365 /// pointer is returned. 366 /// 367 /// @return a pointer to the regular expression object of 368 /// function_suppression::priv::symbol_name_not_regex_str_. 369 const regex::regex_t_sptr get_symbol_name_not_regexpriv370 get_symbol_name_not_regex() const 371 { 372 if (!symbol_name_not_regex_ && !symbol_name_not_regex_str_.empty()) 373 symbol_name_not_regex_ = regex::compile(symbol_name_not_regex_str_); 374 return symbol_name_not_regex_; 375 } 376 377 /// Getter for a pointer to a regular expression object built from 378 /// the regular expression string 379 /// function_suppression::priv::symbol_version_regex_str_. 380 /// 381 /// If that string is empty, then an empty regular expression object 382 /// pointer is returned. 383 /// 384 /// @return a pointer to the regular expression object of 385 /// function_suppression::priv::symbol_version_regex_str_. 386 const regex::regex_t_sptr get_symbol_version_regexpriv387 get_symbol_version_regex() const 388 { 389 if (!symbol_version_regex_ && !symbol_version_regex_str_.empty()) 390 symbol_version_regex_ = regex::compile(symbol_version_regex_str_); 391 return symbol_version_regex_; 392 } 393 }; // end class function_suppression::priv 394 395 bool 396 suppression_matches_function_name(const suppr::function_suppression& s, 397 const string& fn_name); 398 399 bool 400 suppression_matches_function_sym_name(const suppr::function_suppression& s, 401 const string& fn_linkage_name); 402 403 bool 404 suppression_matches_variable_name(const suppr::variable_suppression& s, 405 const string& var_name); 406 407 bool 408 suppression_matches_variable_sym_name(const suppr::variable_suppression& s, 409 const string& var_linkage_name); 410 411 // <variable_suppression stuff> 412 /// The type of the private data of the @ref variable_suppression 413 /// type. 414 struct variable_suppression::priv 415 { 416 friend class variable_suppression; 417 418 change_kind change_kind_; 419 string name_; 420 string name_regex_str_; 421 mutable regex::regex_t_sptr name_regex_; 422 string name_not_regex_str_; 423 mutable regex::regex_t_sptr name_not_regex_; 424 string symbol_name_; 425 string symbol_name_regex_str_; 426 mutable regex::regex_t_sptr symbol_name_regex_; 427 string symbol_name_not_regex_str_; 428 mutable regex::regex_t_sptr symbol_name_not_regex_; 429 string symbol_version_; 430 string symbol_version_regex_str_; 431 mutable regex::regex_t_sptr symbol_version_regex_; 432 string type_name_; 433 string type_name_regex_str_; 434 mutable regex::regex_t_sptr type_name_regex_; 435 privpriv436 priv(const string& name, 437 const string& name_regex_str, 438 const string& symbol_name, 439 const string& symbol_name_regex_str, 440 const string& symbol_version, 441 const string& symbol_version_regex_str, 442 const string& type_name, 443 const string& type_name_regex_str) 444 : change_kind_(ALL_CHANGE_KIND), 445 name_(name), 446 name_regex_str_(name_regex_str), 447 symbol_name_(symbol_name), 448 symbol_name_regex_str_(symbol_name_regex_str), 449 symbol_version_(symbol_version), 450 symbol_version_regex_str_(symbol_version_regex_str), 451 type_name_(type_name), 452 type_name_regex_str_(type_name_regex_str) 453 {} 454 455 /// Getter for a pointer to a regular expression object built from 456 /// the regular expression string 457 /// variable_suppression::priv::name_regex_str_. 458 /// 459 /// If that string is empty, then an empty regular expression object 460 /// pointer is returned. 461 /// 462 /// @return a pointer to the regular expression object of 463 /// variable_suppression::priv::name_regex_str_. 464 const regex::regex_t_sptr get_name_regexpriv465 get_name_regex() const 466 { 467 if (!name_regex_ && !name_regex_str_.empty()) 468 name_regex_ = regex::compile(name_regex_str_); 469 return name_regex_; 470 } 471 472 /// Getter for a pointer to a regular expression object built from 473 /// the regular expression string 474 /// variable_suppression::priv::name_not_regex_str_. 475 /// 476 /// If that string is empty, then an empty regular expression object 477 /// pointer is returned. 478 /// 479 /// @return a pointer to the regular expression object of 480 /// variable_suppression::priv::name_not_regex_str_.. 481 const regex::regex_t_sptr get_name_not_regexpriv482 get_name_not_regex() const 483 { 484 if (!name_not_regex_ && !name_not_regex_str_.empty()) 485 name_not_regex_ = regex::compile(name_not_regex_str_); 486 return name_not_regex_; 487 } 488 489 /// Getter for a pointer to a regular expression object built from 490 /// the regular expression string 491 /// variable_suppression::priv::symbol_name_regex_str_. 492 /// 493 /// If that string is empty, then an empty regular expression object 494 /// pointer is returned. 495 /// 496 /// @return a pointer to the regular expression object of 497 /// variable_suppression::priv::symbol_name_regex_str_. 498 const regex::regex_t_sptr get_symbol_name_regexpriv499 get_symbol_name_regex() const 500 { 501 if (!symbol_name_regex_ && !symbol_name_regex_str_.empty()) 502 symbol_name_regex_ = regex::compile(symbol_name_regex_str_); 503 return symbol_name_regex_; 504 } 505 506 /// Getter for a pointer to a regular expression object built from 507 /// the regular expression string 508 /// variable_suppression::priv::symbol_name_not_regex_str_. 509 /// 510 /// If that string is empty, then an empty regular expression object 511 /// pointer is returned. 512 /// 513 /// @return a pointer to the regular expression object of 514 /// variable_suppression::priv::symbol_name_not_regex_str_. 515 const regex::regex_t_sptr get_symbol_name_not_regexpriv516 get_symbol_name_not_regex() const 517 { 518 if (!symbol_name_not_regex_ && !symbol_name_not_regex_str_.empty()) 519 symbol_name_not_regex_ = regex::compile(symbol_name_not_regex_str_); 520 return symbol_name_not_regex_; 521 } 522 523 /// Getter for a pointer to a regular expression object built from 524 /// the regular expression string 525 /// variable_suppression::priv::symbol_version_regex_str_. 526 /// 527 /// If that string is empty, then an empty regular expression object 528 /// pointer is returned. 529 /// 530 /// @return a pointer to the regular expression object of 531 /// variable_suppression::priv::symbol_version_regex_str_. 532 const regex::regex_t_sptr get_symbol_version_regexpriv533 get_symbol_version_regex() const 534 { 535 if (!symbol_version_regex_ && !symbol_version_regex_str_.empty()) 536 symbol_version_regex_ = regex::compile(symbol_version_regex_str_); 537 return symbol_version_regex_; 538 } 539 540 /// Getter for a pointer to a regular expression object built from 541 /// the regular expression string 542 /// variable_suppression::priv::type_name_regex_str_. 543 /// 544 /// If that string is empty, then an empty regular expression object 545 /// pointer is returned. 546 /// 547 /// @return a pointer to the regular expression object of 548 /// variable_suppression::priv::type_name_regex_str_. 549 const regex::regex_t_sptr get_type_name_regexpriv550 get_type_name_regex() const 551 { 552 if (!type_name_regex_ && !type_name_regex_str_.empty()) 553 type_name_regex_ = regex::compile(type_name_regex_str_); 554 return type_name_regex_; 555 } 556 };// end class variable_supppression::priv 557 558 // </variable_suppression stuff> 559 560 // <type_suppression stuff> 561 /// The private data for @ref type_suppression. 562 class type_suppression::priv 563 { 564 string type_name_regex_str_; 565 mutable regex::regex_t_sptr type_name_regex_; 566 string type_name_; 567 string type_name_not_regex_str_; 568 mutable regex::regex_t_sptr type_name_not_regex_; 569 bool consider_type_kind_; 570 type_suppression::type_kind type_kind_; 571 bool consider_reach_kind_; 572 type_suppression::reach_kind reach_kind_; 573 type_suppression::insertion_ranges insertion_ranges_; 574 unordered_set<string> source_locations_to_keep_; 575 string source_location_to_keep_regex_str_; 576 mutable regex::regex_t_sptr source_location_to_keep_regex_; 577 mutable vector<string> changed_enumerator_names_; 578 579 priv(); 580 581 public: priv(const string & type_name_regexp,const string & type_name,bool consider_type_kind,type_suppression::type_kind type_kind,bool consider_reach_kind,type_suppression::reach_kind reach_kind)582 priv(const string& type_name_regexp, 583 const string& type_name, 584 bool consider_type_kind, 585 type_suppression::type_kind type_kind, 586 bool consider_reach_kind, 587 type_suppression::reach_kind reach_kind) 588 : type_name_regex_str_(type_name_regexp), 589 type_name_(type_name), 590 consider_type_kind_(consider_type_kind), 591 type_kind_(type_kind), 592 consider_reach_kind_(consider_reach_kind), 593 reach_kind_(reach_kind) 594 {} 595 596 /// Get the regular expression object associated to the 'type_name_regex' 597 /// property of @ref type_suppression. 598 /// 599 /// If the regular expression object is not created, this method 600 /// creates it and returns it. 601 /// 602 /// If the 'type_name_regex' property of @ref type_suppression is 603 /// empty then this method returns nil. 604 const regex::regex_t_sptr get_type_name_regex()605 get_type_name_regex() const 606 { 607 if (!type_name_regex_ && !type_name_regex_str_.empty()) 608 type_name_regex_ = regex::compile(type_name_regex_str_); 609 return type_name_regex_; 610 } 611 612 /// Setter for the type_name_regex object. 613 /// 614 /// @param r the new type_name_regex object. 615 void set_type_name_regex(regex::regex_t_sptr r)616 set_type_name_regex(regex::regex_t_sptr r) 617 {type_name_regex_ = r;} 618 619 /// Get the regular expression object associated to the 620 /// 'type_name_not_regex' property of @ref type_suppression. 621 /// 622 /// If the regular expression object is not created, this method 623 /// creates it and returns it. 624 /// 625 /// If the 'type_name_not_regex' property of @ref type_suppression is 626 /// empty then this method returns nil. 627 const regex::regex_t_sptr get_type_name_not_regex()628 get_type_name_not_regex() const 629 { 630 if (!type_name_not_regex_ && !type_name_not_regex_str_.empty()) 631 type_name_not_regex_ = regex::compile(type_name_not_regex_str_); 632 return type_name_not_regex_; 633 } 634 635 /// Setter for the type_name_not_regex object. 636 /// 637 /// @param r the new type_name_not_regex object. 638 void set_type_name_not_regex(regex::regex_t_sptr r)639 set_type_name_not_regex(regex::regex_t_sptr r) 640 {type_name_not_regex_ = r;} 641 642 /// Getter for the string that denotes the 'type_name_not_regex' 643 /// property. 644 /// 645 /// @return the value of the string value of the 646 /// 'type_name_not_regex' property. 647 const string& get_type_name_not_regex_str()648 get_type_name_not_regex_str() const 649 {return type_name_not_regex_str_;} 650 651 /// Setter for the string that denotes the 'type_name_not_regex' 652 /// property. 653 /// 654 /// @return the value of the string value of the 655 /// 'type_name_not_regex' property. 656 void set_type_name_not_regex_str(const string regex_str)657 set_type_name_not_regex_str(const string regex_str) 658 {type_name_not_regex_str_ = regex_str;} 659 660 /// Getter for the source_location_to_keep_regex object. 661 /// 662 /// This function builds the regex if it's not yet built. 663 const regex::regex_t_sptr get_source_location_to_keep_regex()664 get_source_location_to_keep_regex() const 665 { 666 if (!source_location_to_keep_regex_ 667 && !source_location_to_keep_regex_str_.empty()) 668 source_location_to_keep_regex_ = 669 regex::compile(source_location_to_keep_regex_str_); 670 return source_location_to_keep_regex_; 671 } 672 673 /// Setter for the source_location_to_keep_regex object. 674 /// 675 /// @param r the new regex object. 676 void set_source_location_to_keep_regex(regex::regex_t_sptr r)677 set_source_location_to_keep_regex(regex::regex_t_sptr r) 678 {source_location_to_keep_regex_ = r;} 679 680 friend class type_suppression; 681 }; // class type_suppression::priv 682 683 bool 684 suppression_matches_type_name(const suppr::type_suppression& s, 685 const string& type_name); 686 687 bool 688 suppression_matches_type_name(const suppr::type_suppression& s, 689 const scope_decl* scope, 690 const type_base_sptr& type); 691 692 bool 693 suppression_matches_type_location(const type_suppression& s, 694 const location& loc); 695 696 bool 697 suppression_matches_type_location(const type_suppression& s, 698 const type_base_sptr& type); 699 700 bool 701 suppression_matches_type_name_or_location(const type_suppression& s, 702 const string& type_name, 703 const location& type_location); 704 705 // </type_suppression stuff> 706 707 }// end namespace suppr 708 } // end namespace abigail 709 710 #endif // __ABG_SUPPRESSION_PRIV_H__ 711