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