1/* Pointer Bounds Checker IPA passes. 2 Copyright (C) 2014-2015 Free Software Foundation, Inc. 3 Contributed by Ilya Enkovich (ilya.enkovich@intel.com) 4 5This file is part of GCC. 6 7GCC is free software; you can redistribute it and/or modify it under 8the terms of the GNU General Public License as published by the Free 9Software Foundation; either version 3, or (at your option) any later 10version. 11 12GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13WARRANTY; without even the implied warranty of MERCHANTABILITY or 14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15for more details. 16 17You should have received a copy of the GNU General Public License 18along with GCC; see the file COPYING3. If not see 19<http://www.gnu.org/licenses/>. */ 20 21#include "config.h" 22#include "system.h" 23#include "coretypes.h" 24#include "hash-set.h" 25#include "machmode.h" 26#include "vec.h" 27#include "double-int.h" 28#include "input.h" 29#include "alias.h" 30#include "symtab.h" 31#include "options.h" 32#include "wide-int.h" 33#include "inchash.h" 34#include "tree.h" 35#include "fold-const.h" 36#include "stor-layout.h" 37#include "tree-pass.h" 38#include "stringpool.h" 39#include "bitmap.h" 40#include "gimple-expr.h" 41#include "tm.h" 42#include "hard-reg-set.h" 43#include "function.h" 44#include "is-a.h" 45#include "tree-ssa-alias.h" 46#include "predict.h" 47#include "basic-block.h" 48#include "gimple.h" 49#include "ipa-ref.h" 50#include "lto-streamer.h" 51#include "cgraph.h" 52#include "tree-chkp.h" 53#include "tree-inline.h" 54#include "ipa-chkp.h" 55 56/* Pointer Bounds Checker has two IPA passes to support code instrumentation. 57 58 In instrumented code each pointer is provided with bounds. For input 59 pointer parameters it means we also have bounds passed. For calls it 60 means we have additional bounds arguments for pointer arguments. 61 62 To have all IPA optimizations working correctly we have to express 63 dataflow between passed and received bounds explicitly via additional 64 entries in function declaration arguments list and in function type. 65 Since we may have both instrumented and not instrumented code at the 66 same time, we cannot replace all original functions with their 67 instrumented variants. Therefore we create clones (versions) instead. 68 69 Instrumentation clones creation is a separate IPA pass which is a part 70 of early local passes. Clones are created after SSA is built (because 71 instrumentation pass works on SSA) and before any transformations 72 which may change pointer flow and therefore lead to incorrect code 73 instrumentation (possibly causing false bounds check failures). 74 75 Instrumentation clones have pointer bounds arguments added right after 76 pointer arguments. Clones have assembler name of the original 77 function with suffix added. New assembler name is in transparent 78 alias chain with the original name. Thus we expect all calls to the 79 original and instrumented functions look similar in assembler. 80 81 During instrumentation versioning pass we create instrumented versions 82 of all function with body and also for all their aliases and thunks. 83 Clones for functions with no body are created on demand (usually 84 during call instrumentation). 85 86 Original and instrumented function nodes are connected with IPA 87 reference IPA_REF_CHKP. It is mostly done to have reachability 88 analysis working correctly. We may have no references to the 89 instrumented function in the code but it still should be counted 90 as reachable if the original function is reachable. 91 92 When original function bodies are not needed anymore we release 93 them and transform functions into a special kind of thunks. Each 94 thunk has a call edge to the instrumented version. These thunks 95 help to keep externally visible instrumented functions visible 96 when linker resolution files are used. Linker has no info about 97 connection between original and instrumented function and 98 therefore we may wrongly decide (due to difference in assembler 99 names) that instrumented function version is local and can be 100 removed. */ 101 102#define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_" 103#define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_" 104 105/* Return 1 calls to FNDECL should be replaced with 106 a call to wrapper function. */ 107bool 108chkp_wrap_function (tree fndecl) 109{ 110 if (!flag_chkp_use_wrappers) 111 return false; 112 113 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) 114 { 115 switch (DECL_FUNCTION_CODE (fndecl)) 116 { 117 case BUILT_IN_STRLEN: 118 case BUILT_IN_STRCPY: 119 case BUILT_IN_STRNCPY: 120 case BUILT_IN_STPCPY: 121 case BUILT_IN_STPNCPY: 122 case BUILT_IN_STRCAT: 123 case BUILT_IN_STRNCAT: 124 case BUILT_IN_MEMCPY: 125 case BUILT_IN_MEMPCPY: 126 case BUILT_IN_MEMSET: 127 case BUILT_IN_MEMMOVE: 128 case BUILT_IN_BZERO: 129 case BUILT_IN_MALLOC: 130 case BUILT_IN_CALLOC: 131 case BUILT_IN_REALLOC: 132 return 1; 133 134 default: 135 return 0; 136 } 137 } 138 139 return false; 140} 141 142static const char * 143chkp_wrap_function_name (tree fndecl) 144{ 145 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL); 146 147 switch (DECL_FUNCTION_CODE (fndecl)) 148 { 149 case BUILT_IN_STRLEN: 150 return CHKP_WRAPPER_SYMBOL_PREFIX "strlen"; 151 case BUILT_IN_STRCPY: 152 return CHKP_WRAPPER_SYMBOL_PREFIX "strcpy"; 153 case BUILT_IN_STRNCPY: 154 return CHKP_WRAPPER_SYMBOL_PREFIX "strncpy"; 155 case BUILT_IN_STPCPY: 156 return CHKP_WRAPPER_SYMBOL_PREFIX "stpcpy"; 157 case BUILT_IN_STPNCPY: 158 return CHKP_WRAPPER_SYMBOL_PREFIX "stpncpy"; 159 case BUILT_IN_STRCAT: 160 return CHKP_WRAPPER_SYMBOL_PREFIX "strcat"; 161 case BUILT_IN_STRNCAT: 162 return CHKP_WRAPPER_SYMBOL_PREFIX "strncat"; 163 case BUILT_IN_MEMCPY: 164 return CHKP_WRAPPER_SYMBOL_PREFIX "memcpy"; 165 case BUILT_IN_MEMPCPY: 166 return CHKP_WRAPPER_SYMBOL_PREFIX "mempcpy"; 167 case BUILT_IN_MEMSET: 168 return CHKP_WRAPPER_SYMBOL_PREFIX "memset"; 169 case BUILT_IN_MEMMOVE: 170 return CHKP_WRAPPER_SYMBOL_PREFIX "memmove"; 171 case BUILT_IN_BZERO: 172 return CHKP_WRAPPER_SYMBOL_PREFIX "bzero"; 173 case BUILT_IN_MALLOC: 174 return CHKP_WRAPPER_SYMBOL_PREFIX "malloc"; 175 case BUILT_IN_CALLOC: 176 return CHKP_WRAPPER_SYMBOL_PREFIX "calloc"; 177 case BUILT_IN_REALLOC: 178 return CHKP_WRAPPER_SYMBOL_PREFIX "realloc"; 179 180 default: 181 gcc_unreachable (); 182 } 183 184 return ""; 185} 186 187/* Build a clone of FNDECL with a modified name. */ 188 189static tree 190chkp_build_instrumented_fndecl (tree fndecl) 191{ 192 tree new_decl = copy_node (fndecl); 193 tree new_name; 194 std::string s; 195 196 /* called_as_built_in checks DECL_NAME to identify calls to 197 builtins. We want instrumented calls to builtins to be 198 recognized by called_as_built_in. Therefore use original 199 DECL_NAME for cloning with no prefixes. */ 200 s = IDENTIFIER_POINTER (DECL_NAME (fndecl)); 201 s += ".chkp"; 202 DECL_NAME (new_decl) = get_identifier (s.c_str ()); 203 204 /* References to the original and to the instrumented version 205 should look the same in the output assembly. And we cannot 206 use the same assembler name for the instrumented version 207 because it conflicts with decl merging algorithms in LTO. 208 Achieve the result by using transparent alias name for the 209 instrumented version. */ 210 if (chkp_wrap_function(fndecl)) 211 { 212 new_name = get_identifier (chkp_wrap_function_name (fndecl)); 213 DECL_VISIBILITY (new_decl) = VISIBILITY_DEFAULT; 214 } 215 else 216 { 217 s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)); 218 s += ".chkp"; 219 new_name = get_identifier (s.c_str ()); 220 IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1; 221 TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl); 222 } 223 SET_DECL_ASSEMBLER_NAME (new_decl, new_name); 224 225 /* For functions with body versioning will make a copy of arguments. 226 For functions with no body we need to do it here. */ 227 if (!gimple_has_body_p (fndecl)) 228 DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl)); 229 230 /* We are going to modify attributes list and therefore should 231 make own copy. */ 232 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl)); 233 234 /* Change builtin function code. */ 235 if (DECL_BUILT_IN (new_decl)) 236 { 237 gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL); 238 gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS); 239 DECL_FUNCTION_CODE (new_decl) 240 = (enum built_in_function)(DECL_FUNCTION_CODE (new_decl) 241 + BEGIN_CHKP_BUILTINS + 1); 242 } 243 244 return new_decl; 245} 246 247 248/* Fix operands of attribute from ATTRS list named ATTR_NAME. 249 Integer operands are replaced with values according to 250 INDEXES map having LEN elements. For operands out of len 251 we just add DELTA. */ 252 253static void 254chkp_map_attr_arg_indexes (tree attrs, const char *attr_name, 255 unsigned *indexes, int len, int delta) 256{ 257 tree attr = lookup_attribute (attr_name, attrs); 258 tree op; 259 260 if (!attr) 261 return; 262 263 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr)); 264 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op)) 265 { 266 int idx; 267 268 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST) 269 continue; 270 271 idx = TREE_INT_CST_LOW (TREE_VALUE (op)); 272 273 /* If idx exceeds indexes length then we just 274 keep it at the same distance from the last 275 known arg. */ 276 if (idx > len) 277 idx += delta; 278 else 279 idx = indexes[idx - 1] + 1; 280 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx); 281 } 282} 283 284/* Make a copy of function type ORIG_TYPE adding pointer 285 bounds as additional arguments. */ 286 287tree 288chkp_copy_function_type_adding_bounds (tree orig_type) 289{ 290 tree type; 291 tree arg_type, attrs, t; 292 unsigned len = list_length (TYPE_ARG_TYPES (orig_type)); 293 unsigned *indexes = XALLOCAVEC (unsigned, len); 294 unsigned idx = 0, new_idx = 0; 295 296 for (arg_type = TYPE_ARG_TYPES (orig_type); 297 arg_type; 298 arg_type = TREE_CHAIN (arg_type)) 299 if (TREE_VALUE (arg_type) == void_type_node) 300 continue; 301 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type)) 302 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)), 303 TREE_VALUE (arg_type), true) 304 || chkp_type_has_pointer (TREE_VALUE (arg_type))) 305 break; 306 307 /* We may use original type if there are no bounds passed. */ 308 if (!arg_type) 309 return orig_type; 310 311 type = build_distinct_type_copy (orig_type); 312 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type)); 313 314 for (arg_type = TYPE_ARG_TYPES (type); 315 arg_type; 316 arg_type = TREE_CHAIN (arg_type)) 317 { 318 indexes[idx++] = new_idx++; 319 320 /* pass_by_reference returns 1 for void type, 321 so check for it first. */ 322 if (TREE_VALUE (arg_type) == void_type_node) 323 continue; 324 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type)) 325 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)), 326 TREE_VALUE (arg_type), true)) 327 { 328 tree new_type = build_tree_list (NULL_TREE, 329 pointer_bounds_type_node); 330 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type); 331 TREE_CHAIN (arg_type) = new_type; 332 333 arg_type = TREE_CHAIN (arg_type); 334 new_idx++; 335 } 336 else if (chkp_type_has_pointer (TREE_VALUE (arg_type))) 337 { 338 bitmap slots = BITMAP_ALLOC (NULL); 339 bitmap_iterator bi; 340 unsigned bnd_no; 341 342 chkp_find_bound_slots (TREE_VALUE (arg_type), slots); 343 344 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi) 345 { 346 tree new_type = build_tree_list (NULL_TREE, 347 pointer_bounds_type_node); 348 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type); 349 TREE_CHAIN (arg_type) = new_type; 350 351 arg_type = TREE_CHAIN (arg_type); 352 new_idx++; 353 } 354 BITMAP_FREE (slots); 355 } 356 } 357 358 /* If function type has attribute with arg indexes then 359 we have to copy it fixing attribute ops. Map for 360 fixing is in indexes array. */ 361 attrs = TYPE_ATTRIBUTES (type); 362 if (lookup_attribute ("nonnull", attrs) 363 || lookup_attribute ("format", attrs) 364 || lookup_attribute ("format_arg", attrs)) 365 { 366 int delta = new_idx - len; 367 attrs = copy_list (TYPE_ATTRIBUTES (type)); 368 chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta); 369 chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta); 370 chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta); 371 TYPE_ATTRIBUTES (type) = attrs; 372 } 373 374 t = TYPE_MAIN_VARIANT (orig_type); 375 if (orig_type != t) 376 { 377 TYPE_MAIN_VARIANT (type) = t; 378 TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (t); 379 TYPE_NEXT_VARIANT (t) = type; 380 } 381 else 382 { 383 TYPE_MAIN_VARIANT (type) = type; 384 TYPE_NEXT_VARIANT (type) = NULL; 385 } 386 387 388 return type; 389} 390 391/* For given function FNDECL add bounds arguments to arguments 392 list. */ 393 394static void 395chkp_add_bounds_params_to_function (tree fndecl) 396{ 397 tree arg; 398 399 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg)) 400 if (BOUNDED_P (arg)) 401 { 402 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX; 403 tree new_arg; 404 405 if (DECL_NAME (arg)) 406 new_name += IDENTIFIER_POINTER (DECL_NAME (arg)); 407 else 408 { 409 char uid[25]; 410 snprintf (uid, 25, "D.%u", DECL_UID (arg)); 411 new_name += uid; 412 } 413 414 new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL, 415 get_identifier (new_name.c_str ()), 416 pointer_bounds_type_node); 417 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node; 418 DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg); 419 DECL_ARTIFICIAL (new_arg) = 1; 420 DECL_CHAIN (new_arg) = DECL_CHAIN (arg); 421 DECL_CHAIN (arg) = new_arg; 422 423 arg = DECL_CHAIN (arg); 424 425 } 426 else if (chkp_type_has_pointer (TREE_TYPE (arg))) 427 { 428 tree orig_arg = arg; 429 bitmap slots = BITMAP_ALLOC (NULL); 430 bitmap_iterator bi; 431 unsigned bnd_no; 432 433 chkp_find_bound_slots (TREE_TYPE (arg), slots); 434 435 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi) 436 { 437 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX; 438 tree new_arg; 439 char offs[25]; 440 441 if (DECL_NAME (orig_arg)) 442 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg)); 443 else 444 { 445 snprintf (offs, 25, "D.%u", DECL_UID (arg)); 446 new_name += offs; 447 } 448 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT); 449 450 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg), 451 PARM_DECL, 452 get_identifier (new_name.c_str ()), 453 pointer_bounds_type_node); 454 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node; 455 DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg); 456 DECL_ARTIFICIAL (new_arg) = 1; 457 DECL_CHAIN (new_arg) = DECL_CHAIN (arg); 458 DECL_CHAIN (arg) = new_arg; 459 460 arg = DECL_CHAIN (arg); 461 } 462 BITMAP_FREE (slots); 463 } 464 465 TREE_TYPE (fndecl) = 466 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl)); 467} 468 469/* Return an instrumentation clone for builtin function 470 FNDECL. Create one if needed. */ 471 472tree 473chkp_maybe_clone_builtin_fndecl (tree fndecl) 474{ 475 tree clone; 476 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); 477 478 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 479 && fcode < BEGIN_CHKP_BUILTINS); 480 481 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1); 482 clone = builtin_decl_explicit (fcode); 483 if (clone) 484 return clone; 485 486 clone = chkp_build_instrumented_fndecl (fndecl); 487 chkp_add_bounds_params_to_function (clone); 488 489 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode); 490 491 set_builtin_decl (fcode, clone, false); 492 493 return clone; 494} 495 496/* Return 1 if function FNDECL should be instrumented. */ 497 498bool 499chkp_instrumentable_p (tree fndecl) 500{ 501 struct function *fn = DECL_STRUCT_FUNCTION (fndecl); 502 return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl)) 503 && (!flag_chkp_instrument_marked_only 504 || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl))) 505 && (!fn || !copy_forbidden (fn, fndecl))); 506} 507 508/* Return clone created for instrumentation of NODE or NULL. */ 509 510cgraph_node * 511chkp_maybe_create_clone (tree fndecl) 512{ 513 cgraph_node *node = cgraph_node::get_create (fndecl); 514 cgraph_node *clone = node->instrumented_version; 515 516 gcc_assert (!node->instrumentation_clone); 517 518 if (DECL_BUILT_IN (fndecl) 519 && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL 520 || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS)) 521 return NULL; 522 523 clone = node->instrumented_version; 524 525 /* Some instrumented builtin function calls may be optimized and 526 cgraph nodes may be removed as unreachable. Later optimizations 527 may generate new calls to removed functions and in this case 528 we have to recreate cgraph node. FUNCTION_DECL for instrumented 529 builtin still exists and should be reused in such case. */ 530 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL 531 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)) 532 && !clone) 533 { 534 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl); 535 tree new_decl; 536 537 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1); 538 new_decl = builtin_decl_explicit (fncode); 539 540 /* We've actually already created an instrumented clone once. 541 Restore it. */ 542 if (new_decl) 543 { 544 clone = cgraph_node::get (new_decl); 545 546 if (!clone) 547 { 548 gcc_assert (!gimple_has_body_p (fndecl)); 549 clone = cgraph_node::get_create (new_decl); 550 clone->externally_visible = node->externally_visible; 551 clone->local = node->local; 552 clone->address_taken = node->address_taken; 553 clone->thunk = node->thunk; 554 clone->alias = node->alias; 555 clone->weakref = node->weakref; 556 clone->cpp_implicit_alias = node->cpp_implicit_alias; 557 clone->orig_decl = fndecl; 558 clone->instrumentation_clone = true; 559 } 560 561 clone->instrumented_version = node; 562 node->instrumented_version = clone; 563 } 564 } 565 566 if (!clone) 567 { 568 tree new_decl = chkp_build_instrumented_fndecl (fndecl); 569 struct cgraph_edge *e; 570 struct ipa_ref *ref; 571 int i; 572 573 clone = node->create_version_clone (new_decl, vNULL, NULL); 574 clone->externally_visible = node->externally_visible; 575 clone->local = node->local; 576 clone->address_taken = node->address_taken; 577 clone->thunk = node->thunk; 578 clone->alias = node->alias; 579 clone->weakref = node->weakref; 580 clone->cpp_implicit_alias = node->cpp_implicit_alias; 581 clone->instrumented_version = node; 582 clone->orig_decl = fndecl; 583 clone->instrumentation_clone = true; 584 node->instrumented_version = clone; 585 586 if (gimple_has_body_p (fndecl)) 587 { 588 gcc_assert (chkp_instrumentable_p (fndecl)); 589 tree_function_versioning (fndecl, new_decl, NULL, false, 590 NULL, false, NULL, NULL); 591 clone->lowered = true; 592 } 593 594 /* New params are inserted after versioning because it 595 actually copies args list from the original decl. */ 596 chkp_add_bounds_params_to_function (new_decl); 597 598 /* Remember builtin fndecl. */ 599 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL 600 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))) 601 { 602 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl))); 603 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl), 604 clone->decl, false); 605 } 606 607 /* Clones have the same comdat group as originals. */ 608 if (node->same_comdat_group 609 || (DECL_ONE_ONLY (node->decl) 610 && !DECL_EXTERNAL (node->decl))) 611 clone->add_to_same_comdat_group (node); 612 613 if (gimple_has_body_p (fndecl)) 614 symtab->call_cgraph_insertion_hooks (clone); 615 616 /* Clone all aliases. */ 617 for (i = 0; node->iterate_direct_aliases (i, ref); i++) 618 chkp_maybe_create_clone (ref->referring->decl); 619 620 /* Clone all thunks. */ 621 for (e = node->callers; e; e = e->next_caller) 622 if (e->caller->thunk.thunk_p 623 && !e->caller->thunk.add_pointer_bounds_args 624 && !e->caller->instrumentation_clone) 625 { 626 struct cgraph_node *thunk 627 = chkp_maybe_create_clone (e->caller->decl); 628 /* Redirect thunk clone edge to the node clone. */ 629 thunk->callees->redirect_callee (clone); 630 } 631 632 /* For aliases and thunks we should make sure target is cloned 633 to have proper references and edges. */ 634 if (node->thunk.thunk_p) 635 chkp_maybe_create_clone (node->callees->callee->decl); 636 else if (node->alias) 637 { 638 struct cgraph_node *target; 639 640 ref = node->ref_list.first_reference (); 641 if (ref) 642 { 643 target = chkp_maybe_create_clone (ref->referred->decl); 644 clone->create_reference (target, IPA_REF_ALIAS); 645 } 646 647 if (node->alias_target) 648 { 649 if (TREE_CODE (node->alias_target) == FUNCTION_DECL) 650 { 651 target = chkp_maybe_create_clone (node->alias_target); 652 clone->alias_target = target->decl; 653 } 654 else 655 clone->alias_target = node->alias_target; 656 } 657 } 658 659 /* Add IPA reference. It's main role is to keep instrumented 660 version reachable while original node is reachable. */ 661 ref = node->create_reference (clone, IPA_REF_CHKP, NULL); 662 } 663 664 return clone; 665} 666 667/* Create clone for all functions to be instrumented. */ 668 669static unsigned int 670chkp_versioning (void) 671{ 672 struct cgraph_node *node; 673 const char *reason; 674 675 bitmap_obstack_initialize (NULL); 676 677 FOR_EACH_DEFINED_FUNCTION (node) 678 { 679 if (!node->instrumentation_clone 680 && !node->instrumented_version 681 && !node->alias 682 && !node->thunk.thunk_p 683 && (!DECL_BUILT_IN (node->decl) 684 || (DECL_BUILT_IN_CLASS (node->decl) == BUILT_IN_NORMAL 685 && DECL_FUNCTION_CODE (node->decl) < BEGIN_CHKP_BUILTINS))) 686 { 687 if (chkp_instrumentable_p (node->decl)) 688 chkp_maybe_create_clone (node->decl); 689 else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl), 690 node->decl))) 691 { 692 if (warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wchkp, 693 "function cannot be instrumented")) 694 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl); 695 } 696 } 697 } 698 699 /* Mark all aliases and thunks of functions with no instrumented 700 version as legacy function. */ 701 FOR_EACH_DEFINED_FUNCTION (node) 702 { 703 if (!node->instrumentation_clone 704 && !node->instrumented_version 705 && (node->alias || node->thunk.thunk_p) 706 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl))) 707 DECL_ATTRIBUTES (node->decl) 708 = tree_cons (get_identifier ("bnd_legacy"), NULL, 709 DECL_ATTRIBUTES (node->decl)); 710 } 711 712 bitmap_obstack_release (NULL); 713 714 return 0; 715} 716 717/* In this pass we remove bodies of functions having 718 instrumented version. Functions with removed bodies 719 become a special kind of thunks to provide a connection 720 between calls to the original version and instrumented 721 function. */ 722 723static unsigned int 724chkp_produce_thunks (bool early) 725{ 726 struct cgraph_node *node; 727 728 FOR_EACH_DEFINED_FUNCTION (node) 729 { 730 if (!node->instrumentation_clone 731 && node->instrumented_version 732 && gimple_has_body_p (node->decl) 733 && gimple_has_body_p (node->instrumented_version->decl) 734 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl)) 735 || !early)) 736 { 737 node->release_body (); 738 node->remove_callees (); 739 node->remove_all_references (); 740 741 node->thunk.thunk_p = true; 742 node->thunk.add_pointer_bounds_args = true; 743 node->create_edge (node->instrumented_version, NULL, 744 0, CGRAPH_FREQ_BASE); 745 node->create_reference (node->instrumented_version, 746 IPA_REF_CHKP, NULL); 747 /* Thunk shouldn't be a cdtor. */ 748 DECL_STATIC_CONSTRUCTOR (node->decl) = 0; 749 DECL_STATIC_DESTRUCTOR (node->decl) = 0; 750 } 751 } 752 753 /* Mark instrumentation clones created for aliases and thunks 754 as insttrumented so they could be removed as unreachable 755 now. */ 756 if (!early) 757 { 758 FOR_EACH_DEFINED_FUNCTION (node) 759 { 760 if (node->instrumentation_clone 761 && (node->alias || node->thunk.thunk_p) 762 && !chkp_function_instrumented_p (node->decl)) 763 chkp_function_mark_instrumented (node->decl); 764 } 765 } 766 767 return TODO_remove_functions; 768} 769 770const pass_data pass_data_ipa_chkp_versioning = 771{ 772 SIMPLE_IPA_PASS, /* type */ 773 "chkp_versioning", /* name */ 774 OPTGROUP_NONE, /* optinfo_flags */ 775 TV_NONE, /* tv_id */ 776 0, /* properties_required */ 777 0, /* properties_provided */ 778 0, /* properties_destroyed */ 779 0, /* todo_flags_start */ 780 0 /* todo_flags_finish */ 781}; 782 783const pass_data pass_data_ipa_chkp_early_produce_thunks = 784{ 785 SIMPLE_IPA_PASS, /* type */ 786 "chkp_ecleanup", /* name */ 787 OPTGROUP_NONE, /* optinfo_flags */ 788 TV_NONE, /* tv_id */ 789 0, /* properties_required */ 790 0, /* properties_provided */ 791 0, /* properties_destroyed */ 792 0, /* todo_flags_start */ 793 0 /* todo_flags_finish */ 794}; 795 796const pass_data pass_data_ipa_chkp_produce_thunks = 797{ 798 SIMPLE_IPA_PASS, /* type */ 799 "chkp_cleanup", /* name */ 800 OPTGROUP_NONE, /* optinfo_flags */ 801 TV_NONE, /* tv_id */ 802 0, /* properties_required */ 803 0, /* properties_provided */ 804 0, /* properties_destroyed */ 805 0, /* todo_flags_start */ 806 0 /* todo_flags_finish */ 807}; 808 809class pass_ipa_chkp_versioning : public simple_ipa_opt_pass 810{ 811public: 812 pass_ipa_chkp_versioning (gcc::context *ctxt) 813 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt) 814 {} 815 816 /* opt_pass methods: */ 817 virtual opt_pass * clone () 818 { 819 return new pass_ipa_chkp_versioning (m_ctxt); 820 } 821 822 virtual bool gate (function *) 823 { 824 return flag_check_pointer_bounds; 825 } 826 827 virtual unsigned int execute (function *) 828 { 829 return chkp_versioning (); 830 } 831 832}; // class pass_ipa_chkp_versioning 833 834class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass 835{ 836public: 837 pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt) 838 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt) 839 {} 840 841 /* opt_pass methods: */ 842 virtual opt_pass * clone () 843 { 844 return new pass_ipa_chkp_early_produce_thunks (m_ctxt); 845 } 846 847 virtual bool gate (function *) 848 { 849 return flag_check_pointer_bounds; 850 } 851 852 virtual unsigned int execute (function *) 853 { 854 return chkp_produce_thunks (true); 855 } 856 857}; // class pass_chkp_produce_thunks 858 859class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass 860{ 861public: 862 pass_ipa_chkp_produce_thunks (gcc::context *ctxt) 863 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt) 864 {} 865 866 /* opt_pass methods: */ 867 virtual opt_pass * clone () 868 { 869 return new pass_ipa_chkp_produce_thunks (m_ctxt); 870 } 871 872 virtual bool gate (function *) 873 { 874 return flag_check_pointer_bounds; 875 } 876 877 virtual unsigned int execute (function *) 878 { 879 return chkp_produce_thunks (false); 880 } 881 882}; // class pass_chkp_produce_thunks 883 884simple_ipa_opt_pass * 885make_pass_ipa_chkp_versioning (gcc::context *ctxt) 886{ 887 return new pass_ipa_chkp_versioning (ctxt); 888} 889 890simple_ipa_opt_pass * 891make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt) 892{ 893 return new pass_ipa_chkp_early_produce_thunks (ctxt); 894} 895 896simple_ipa_opt_pass * 897make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt) 898{ 899 return new pass_ipa_chkp_produce_thunks (ctxt); 900} 901