* omp-low.c (lower_omp_target): Remove unreachable code & merge
[official-gcc.git] / gcc / ipa-chkp.c
blob8299d6d44810bf46d69445300d6dde41d7b7a943
1 /* Pointer Bounds Checker IPA passes.
2 Copyright (C) 2014-2015 Free Software Foundation, Inc.
3 Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
5 This file is part of GCC.
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.
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.
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/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "hard-reg-set.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 "alias.h"
32 #include "fold-const.h"
33 #include "stor-layout.h"
34 #include "calls.h"
35 #include "cgraph.h"
36 #include "tree-chkp.h"
37 #include "tree-inline.h"
38 #include "ipa-chkp.h"
40 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
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.
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.
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).
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.
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).
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.
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. */
86 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
87 #define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
89 /* Return 1 calls to FNDECL should be replaced with
90 a call to wrapper function. */
91 bool
92 chkp_wrap_function (tree fndecl)
94 if (!flag_chkp_use_wrappers)
95 return false;
97 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
99 switch (DECL_FUNCTION_CODE (fndecl))
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;
118 default:
119 return 0;
123 return false;
126 static const char *
127 chkp_wrap_function_name (tree fndecl)
129 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL);
131 switch (DECL_FUNCTION_CODE (fndecl))
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";
164 default:
165 gcc_unreachable ();
168 return "";
171 /* Build a clone of FNDECL with a modified name. */
173 static tree
174 chkp_build_instrumented_fndecl (tree fndecl)
176 tree new_decl = copy_node (fndecl);
177 tree new_name;
178 std::string s;
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 ());
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))
196 new_name = get_identifier (chkp_wrap_function_name (fndecl));
197 DECL_VISIBILITY (new_decl) = VISIBILITY_DEFAULT;
199 else
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);
207 SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
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 DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
214 /* We are going to modify attributes list and therefore should
215 make own copy. */
216 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
218 /* Change builtin function code. */
219 if (DECL_BUILT_IN (new_decl))
221 gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL);
222 gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS);
223 DECL_FUNCTION_CODE (new_decl)
224 = (enum built_in_function)(DECL_FUNCTION_CODE (new_decl)
225 + BEGIN_CHKP_BUILTINS + 1);
228 return new_decl;
232 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
233 Integer operands are replaced with values according to
234 INDEXES map having LEN elements. For operands out of len
235 we just add DELTA. */
237 static void
238 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
239 unsigned *indexes, int len, int delta)
241 tree attr = lookup_attribute (attr_name, attrs);
242 tree op;
244 if (!attr)
245 return;
247 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
248 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
250 int idx;
252 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
253 continue;
255 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
257 /* If idx exceeds indexes length then we just
258 keep it at the same distance from the last
259 known arg. */
260 if (idx > len)
261 idx += delta;
262 else
263 idx = indexes[idx - 1] + 1;
264 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
268 /* Make a copy of function type ORIG_TYPE adding pointer
269 bounds as additional arguments. */
271 tree
272 chkp_copy_function_type_adding_bounds (tree orig_type)
274 tree type;
275 tree arg_type, attrs;
276 unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
277 unsigned *indexes = XALLOCAVEC (unsigned, len);
278 unsigned idx = 0, new_idx = 0;
280 for (arg_type = TYPE_ARG_TYPES (orig_type);
281 arg_type;
282 arg_type = TREE_CHAIN (arg_type))
283 if (TREE_VALUE (arg_type) == void_type_node)
284 continue;
285 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
286 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
287 TREE_VALUE (arg_type), true)
288 || chkp_type_has_pointer (TREE_VALUE (arg_type)))
289 break;
291 /* We may use original type if there are no bounds passed. */
292 if (!arg_type)
293 return orig_type;
295 type = build_distinct_type_copy (orig_type);
296 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
298 for (arg_type = TYPE_ARG_TYPES (type);
299 arg_type;
300 arg_type = TREE_CHAIN (arg_type))
302 indexes[idx++] = new_idx++;
304 /* pass_by_reference returns 1 for void type,
305 so check for it first. */
306 if (TREE_VALUE (arg_type) == void_type_node)
307 continue;
308 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
309 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
310 TREE_VALUE (arg_type), true))
312 tree new_type = build_tree_list (NULL_TREE,
313 pointer_bounds_type_node);
314 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
315 TREE_CHAIN (arg_type) = new_type;
317 arg_type = TREE_CHAIN (arg_type);
318 new_idx++;
320 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
322 bitmap slots = BITMAP_ALLOC (NULL);
323 bitmap_iterator bi;
324 unsigned bnd_no;
326 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
328 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
330 tree new_type = build_tree_list (NULL_TREE,
331 pointer_bounds_type_node);
332 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
333 TREE_CHAIN (arg_type) = new_type;
335 arg_type = TREE_CHAIN (arg_type);
336 new_idx++;
338 BITMAP_FREE (slots);
342 /* If function type has attribute with arg indexes then
343 we have to copy it fixing attribute ops. Map for
344 fixing is in indexes array. */
345 attrs = TYPE_ATTRIBUTES (type);
346 if (lookup_attribute ("nonnull", attrs)
347 || lookup_attribute ("format", attrs)
348 || lookup_attribute ("format_arg", attrs))
350 int delta = new_idx - len;
351 attrs = copy_list (TYPE_ATTRIBUTES (type));
352 chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
353 chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
354 chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
355 TYPE_ATTRIBUTES (type) = attrs;
358 return type;
361 /* For given function FNDECL add bounds arguments to arguments
362 list. */
364 static void
365 chkp_add_bounds_params_to_function (tree fndecl)
367 tree arg;
369 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
370 if (BOUNDED_P (arg))
372 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
373 tree new_arg;
375 if (DECL_NAME (arg))
376 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
377 else
379 char uid[25];
380 snprintf (uid, 25, "D.%u", DECL_UID (arg));
381 new_name += uid;
384 new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
385 get_identifier (new_name.c_str ()),
386 pointer_bounds_type_node);
387 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
388 DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
389 DECL_ARTIFICIAL (new_arg) = 1;
390 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
391 DECL_CHAIN (arg) = new_arg;
393 arg = DECL_CHAIN (arg);
396 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
398 tree orig_arg = arg;
399 bitmap slots = BITMAP_ALLOC (NULL);
400 bitmap_iterator bi;
401 unsigned bnd_no;
403 chkp_find_bound_slots (TREE_TYPE (arg), slots);
405 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
407 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
408 tree new_arg;
409 char offs[25];
411 if (DECL_NAME (orig_arg))
412 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
413 else
415 snprintf (offs, 25, "D.%u", DECL_UID (arg));
416 new_name += offs;
418 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
420 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
421 PARM_DECL,
422 get_identifier (new_name.c_str ()),
423 pointer_bounds_type_node);
424 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
425 DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
426 DECL_ARTIFICIAL (new_arg) = 1;
427 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
428 DECL_CHAIN (arg) = new_arg;
430 arg = DECL_CHAIN (arg);
432 BITMAP_FREE (slots);
435 TREE_TYPE (fndecl) =
436 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
439 /* Return an instrumentation clone for builtin function
440 FNDECL. Create one if needed. */
442 tree
443 chkp_maybe_clone_builtin_fndecl (tree fndecl)
445 tree clone;
446 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
448 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
449 && fcode < BEGIN_CHKP_BUILTINS);
451 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
452 clone = builtin_decl_explicit (fcode);
453 if (clone)
454 return clone;
456 clone = chkp_build_instrumented_fndecl (fndecl);
457 chkp_add_bounds_params_to_function (clone);
459 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
461 set_builtin_decl (fcode, clone, false);
463 return clone;
466 /* Return 1 if function FNDECL should be instrumented. */
468 bool
469 chkp_instrumentable_p (tree fndecl)
471 struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
472 return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
473 && (!flag_chkp_instrument_marked_only
474 || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl)))
475 && (!fn || !copy_forbidden (fn, fndecl)));
478 /* Return clone created for instrumentation of NODE or NULL. */
480 cgraph_node *
481 chkp_maybe_create_clone (tree fndecl)
483 cgraph_node *node = cgraph_node::get_create (fndecl);
484 cgraph_node *clone = node->instrumented_version;
486 gcc_assert (!node->instrumentation_clone);
488 if (DECL_BUILT_IN (fndecl)
489 && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
490 || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
491 return NULL;
493 clone = node->instrumented_version;
495 /* Some instrumented builtin function calls may be optimized and
496 cgraph nodes may be removed as unreachable. Later optimizations
497 may generate new calls to removed functions and in this case
498 we have to recreate cgraph node. FUNCTION_DECL for instrumented
499 builtin still exists and should be reused in such case. */
500 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
501 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))
502 && !clone)
504 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
505 tree new_decl;
507 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
508 new_decl = builtin_decl_explicit (fncode);
510 /* We've actually already created an instrumented clone once.
511 Restore it. */
512 if (new_decl)
514 clone = cgraph_node::get (new_decl);
516 if (!clone)
518 gcc_assert (!gimple_has_body_p (fndecl));
519 clone = cgraph_node::get_create (new_decl);
520 clone->externally_visible = node->externally_visible;
521 clone->local = node->local;
522 clone->address_taken = node->address_taken;
523 clone->thunk = node->thunk;
524 clone->alias = node->alias;
525 clone->weakref = node->weakref;
526 clone->cpp_implicit_alias = node->cpp_implicit_alias;
527 clone->orig_decl = fndecl;
528 clone->instrumentation_clone = true;
531 clone->instrumented_version = node;
532 node->instrumented_version = clone;
536 if (!clone)
538 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
539 struct cgraph_edge *e;
540 struct ipa_ref *ref;
541 int i;
543 clone = node->create_version_clone (new_decl, vNULL, NULL);
544 clone->externally_visible = node->externally_visible;
545 clone->local = node->local;
546 clone->address_taken = node->address_taken;
547 clone->thunk = node->thunk;
548 clone->alias = node->alias;
549 clone->weakref = node->weakref;
550 clone->cpp_implicit_alias = node->cpp_implicit_alias;
551 clone->instrumented_version = node;
552 clone->orig_decl = fndecl;
553 clone->instrumentation_clone = true;
554 node->instrumented_version = clone;
556 if (gimple_has_body_p (fndecl))
558 gcc_assert (chkp_instrumentable_p (fndecl));
559 tree_function_versioning (fndecl, new_decl, NULL, false,
560 NULL, false, NULL, NULL);
561 clone->lowered = true;
564 /* New params are inserted after versioning because it
565 actually copies args list from the original decl. */
566 chkp_add_bounds_params_to_function (new_decl);
568 /* Remember builtin fndecl. */
569 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
570 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
572 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
573 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
574 clone->decl, false);
577 /* Clones have the same comdat group as originals. */
578 if (node->same_comdat_group
579 || (DECL_ONE_ONLY (node->decl)
580 && !DECL_EXTERNAL (node->decl)))
581 clone->add_to_same_comdat_group (node);
583 if (gimple_has_body_p (fndecl))
584 symtab->call_cgraph_insertion_hooks (clone);
586 /* Clone all aliases. */
587 for (i = 0; node->iterate_direct_aliases (i, ref); i++)
588 chkp_maybe_create_clone (ref->referring->decl);
590 /* Clone all thunks. */
591 for (e = node->callers; e; e = e->next_caller)
592 if (e->caller->thunk.thunk_p
593 && !e->caller->thunk.add_pointer_bounds_args
594 && !e->caller->instrumentation_clone)
596 struct cgraph_node *thunk
597 = chkp_maybe_create_clone (e->caller->decl);
598 /* Redirect thunk clone edge to the node clone. */
599 thunk->callees->redirect_callee (clone);
602 /* For aliases and thunks we should make sure target is cloned
603 to have proper references and edges. */
604 if (node->thunk.thunk_p)
605 chkp_maybe_create_clone (node->callees->callee->decl);
606 else if (node->alias)
608 struct cgraph_node *target;
610 ref = node->ref_list.first_reference ();
611 if (ref)
613 target = chkp_maybe_create_clone (ref->referred->decl);
614 clone->create_reference (target, IPA_REF_ALIAS);
617 if (node->alias_target)
619 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
621 target = chkp_maybe_create_clone (node->alias_target);
622 clone->alias_target = target->decl;
624 else
625 clone->alias_target = node->alias_target;
629 /* Add IPA reference. It's main role is to keep instrumented
630 version reachable while original node is reachable. */
631 ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
634 return clone;
637 /* Create clone for all functions to be instrumented. */
639 static unsigned int
640 chkp_versioning (void)
642 struct cgraph_node *node;
643 const char *reason;
645 bitmap_obstack_initialize (NULL);
647 FOR_EACH_DEFINED_FUNCTION (node)
649 if (!node->instrumentation_clone
650 && !node->instrumented_version
651 && !node->alias
652 && !node->thunk.thunk_p
653 && (!DECL_BUILT_IN (node->decl)
654 || (DECL_BUILT_IN_CLASS (node->decl) == BUILT_IN_NORMAL
655 && DECL_FUNCTION_CODE (node->decl) < BEGIN_CHKP_BUILTINS)))
657 if (chkp_instrumentable_p (node->decl))
658 chkp_maybe_create_clone (node->decl);
659 else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl),
660 node->decl)))
662 if (warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wchkp,
663 "function cannot be instrumented"))
664 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
669 /* Mark all aliases and thunks of functions with no instrumented
670 version as legacy function. */
671 FOR_EACH_DEFINED_FUNCTION (node)
673 if (!node->instrumentation_clone
674 && !node->instrumented_version
675 && (node->alias || node->thunk.thunk_p)
676 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
677 DECL_ATTRIBUTES (node->decl)
678 = tree_cons (get_identifier ("bnd_legacy"), NULL,
679 DECL_ATTRIBUTES (node->decl));
682 bitmap_obstack_release (NULL);
684 return 0;
687 /* In this pass we remove bodies of functions having
688 instrumented version. Functions with removed bodies
689 become a special kind of thunks to provide a connection
690 between calls to the original version and instrumented
691 function. */
693 static unsigned int
694 chkp_produce_thunks (bool early)
696 struct cgraph_node *node;
698 FOR_EACH_DEFINED_FUNCTION (node)
700 if (!node->instrumentation_clone
701 && node->instrumented_version
702 && gimple_has_body_p (node->decl)
703 && gimple_has_body_p (node->instrumented_version->decl)
704 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
705 || !early))
707 node->release_body ();
708 node->remove_callees ();
709 node->remove_all_references ();
711 node->thunk.thunk_p = true;
712 node->thunk.add_pointer_bounds_args = true;
713 node->create_edge (node->instrumented_version, NULL,
714 0, CGRAPH_FREQ_BASE);
715 node->create_reference (node->instrumented_version,
716 IPA_REF_CHKP, NULL);
717 /* Thunk shouldn't be a cdtor. */
718 DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
719 DECL_STATIC_DESTRUCTOR (node->decl) = 0;
723 /* Mark instrumentation clones created for aliases and thunks
724 as insttrumented so they could be removed as unreachable
725 now. */
726 if (!early)
728 FOR_EACH_DEFINED_FUNCTION (node)
730 if (node->instrumentation_clone
731 && (node->alias || node->thunk.thunk_p)
732 && !chkp_function_instrumented_p (node->decl))
733 chkp_function_mark_instrumented (node->decl);
737 return TODO_remove_functions;
740 const pass_data pass_data_ipa_chkp_versioning =
742 SIMPLE_IPA_PASS, /* type */
743 "chkp_versioning", /* name */
744 OPTGROUP_NONE, /* optinfo_flags */
745 TV_NONE, /* tv_id */
746 0, /* properties_required */
747 0, /* properties_provided */
748 0, /* properties_destroyed */
749 0, /* todo_flags_start */
750 0 /* todo_flags_finish */
753 const pass_data pass_data_ipa_chkp_early_produce_thunks =
755 SIMPLE_IPA_PASS, /* type */
756 "chkp_ecleanup", /* name */
757 OPTGROUP_NONE, /* optinfo_flags */
758 TV_NONE, /* tv_id */
759 0, /* properties_required */
760 0, /* properties_provided */
761 0, /* properties_destroyed */
762 0, /* todo_flags_start */
763 0 /* todo_flags_finish */
766 const pass_data pass_data_ipa_chkp_produce_thunks =
768 SIMPLE_IPA_PASS, /* type */
769 "chkp_cleanup", /* name */
770 OPTGROUP_NONE, /* optinfo_flags */
771 TV_NONE, /* tv_id */
772 0, /* properties_required */
773 0, /* properties_provided */
774 0, /* properties_destroyed */
775 0, /* todo_flags_start */
776 0 /* todo_flags_finish */
779 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
781 public:
782 pass_ipa_chkp_versioning (gcc::context *ctxt)
783 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
786 /* opt_pass methods: */
787 virtual opt_pass * clone ()
789 return new pass_ipa_chkp_versioning (m_ctxt);
792 virtual bool gate (function *)
794 return flag_check_pointer_bounds;
797 virtual unsigned int execute (function *)
799 return chkp_versioning ();
802 }; // class pass_ipa_chkp_versioning
804 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
806 public:
807 pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
808 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
811 /* opt_pass methods: */
812 virtual opt_pass * clone ()
814 return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
817 virtual bool gate (function *)
819 return flag_check_pointer_bounds;
822 virtual unsigned int execute (function *)
824 return chkp_produce_thunks (true);
827 }; // class pass_chkp_produce_thunks
829 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
831 public:
832 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
833 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
836 /* opt_pass methods: */
837 virtual opt_pass * clone ()
839 return new pass_ipa_chkp_produce_thunks (m_ctxt);
842 virtual bool gate (function *)
844 return flag_check_pointer_bounds;
847 virtual unsigned int execute (function *)
849 return chkp_produce_thunks (false);
852 }; // class pass_chkp_produce_thunks
854 simple_ipa_opt_pass *
855 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
857 return new pass_ipa_chkp_versioning (ctxt);
860 simple_ipa_opt_pass *
861 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
863 return new pass_ipa_chkp_early_produce_thunks (ctxt);
866 simple_ipa_opt_pass *
867 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
869 return new pass_ipa_chkp_produce_thunks (ctxt);