2015-06-11 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / ipa-chkp.c
blobf3d7c73420dd8401384c7a6c791b7470c90a81fa
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 "input.h"
25 #include "alias.h"
26 #include "symtab.h"
27 #include "options.h"
28 #include "tree.h"
29 #include "fold-const.h"
30 #include "stor-layout.h"
31 #include "tree-pass.h"
32 #include "stringpool.h"
33 #include "bitmap.h"
34 #include "gimple-expr.h"
35 #include "tm.h"
36 #include "hard-reg-set.h"
37 #include "function.h"
38 #include "is-a.h"
39 #include "tree-ssa-alias.h"
40 #include "predict.h"
41 #include "basic-block.h"
42 #include "gimple.h"
43 #include "ipa-ref.h"
44 #include "lto-streamer.h"
45 #include "cgraph.h"
46 #include "tree-chkp.h"
47 #include "tree-inline.h"
48 #include "ipa-chkp.h"
50 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
52 In instrumented code each pointer is provided with bounds. For input
53 pointer parameters it means we also have bounds passed. For calls it
54 means we have additional bounds arguments for pointer arguments.
56 To have all IPA optimizations working correctly we have to express
57 dataflow between passed and received bounds explicitly via additional
58 entries in function declaration arguments list and in function type.
59 Since we may have both instrumented and not instrumented code at the
60 same time, we cannot replace all original functions with their
61 instrumented variants. Therefore we create clones (versions) instead.
63 Instrumentation clones creation is a separate IPA pass which is a part
64 of early local passes. Clones are created after SSA is built (because
65 instrumentation pass works on SSA) and before any transformations
66 which may change pointer flow and therefore lead to incorrect code
67 instrumentation (possibly causing false bounds check failures).
69 Instrumentation clones have pointer bounds arguments added right after
70 pointer arguments. Clones have assembler name of the original
71 function with suffix added. New assembler name is in transparent
72 alias chain with the original name. Thus we expect all calls to the
73 original and instrumented functions look similar in assembler.
75 During instrumentation versioning pass we create instrumented versions
76 of all function with body and also for all their aliases and thunks.
77 Clones for functions with no body are created on demand (usually
78 during call instrumentation).
80 Original and instrumented function nodes are connected with IPA
81 reference IPA_REF_CHKP. It is mostly done to have reachability
82 analysis working correctly. We may have no references to the
83 instrumented function in the code but it still should be counted
84 as reachable if the original function is reachable.
86 When original function bodies are not needed anymore we release
87 them and transform functions into a special kind of thunks. Each
88 thunk has a call edge to the instrumented version. These thunks
89 help to keep externally visible instrumented functions visible
90 when linker resolution files are used. Linker has no info about
91 connection between original and instrumented function and
92 therefore we may wrongly decide (due to difference in assembler
93 names) that instrumented function version is local and can be
94 removed. */
96 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
97 #define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
99 /* Return 1 calls to FNDECL should be replaced with
100 a call to wrapper function. */
101 bool
102 chkp_wrap_function (tree fndecl)
104 if (!flag_chkp_use_wrappers)
105 return false;
107 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
109 switch (DECL_FUNCTION_CODE (fndecl))
111 case BUILT_IN_STRLEN:
112 case BUILT_IN_STRCPY:
113 case BUILT_IN_STRNCPY:
114 case BUILT_IN_STPCPY:
115 case BUILT_IN_STPNCPY:
116 case BUILT_IN_STRCAT:
117 case BUILT_IN_STRNCAT:
118 case BUILT_IN_MEMCPY:
119 case BUILT_IN_MEMPCPY:
120 case BUILT_IN_MEMSET:
121 case BUILT_IN_MEMMOVE:
122 case BUILT_IN_BZERO:
123 case BUILT_IN_MALLOC:
124 case BUILT_IN_CALLOC:
125 case BUILT_IN_REALLOC:
126 return 1;
128 default:
129 return 0;
133 return false;
136 static const char *
137 chkp_wrap_function_name (tree fndecl)
139 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL);
141 switch (DECL_FUNCTION_CODE (fndecl))
143 case BUILT_IN_STRLEN:
144 return CHKP_WRAPPER_SYMBOL_PREFIX "strlen";
145 case BUILT_IN_STRCPY:
146 return CHKP_WRAPPER_SYMBOL_PREFIX "strcpy";
147 case BUILT_IN_STRNCPY:
148 return CHKP_WRAPPER_SYMBOL_PREFIX "strncpy";
149 case BUILT_IN_STPCPY:
150 return CHKP_WRAPPER_SYMBOL_PREFIX "stpcpy";
151 case BUILT_IN_STPNCPY:
152 return CHKP_WRAPPER_SYMBOL_PREFIX "stpncpy";
153 case BUILT_IN_STRCAT:
154 return CHKP_WRAPPER_SYMBOL_PREFIX "strcat";
155 case BUILT_IN_STRNCAT:
156 return CHKP_WRAPPER_SYMBOL_PREFIX "strncat";
157 case BUILT_IN_MEMCPY:
158 return CHKP_WRAPPER_SYMBOL_PREFIX "memcpy";
159 case BUILT_IN_MEMPCPY:
160 return CHKP_WRAPPER_SYMBOL_PREFIX "mempcpy";
161 case BUILT_IN_MEMSET:
162 return CHKP_WRAPPER_SYMBOL_PREFIX "memset";
163 case BUILT_IN_MEMMOVE:
164 return CHKP_WRAPPER_SYMBOL_PREFIX "memmove";
165 case BUILT_IN_BZERO:
166 return CHKP_WRAPPER_SYMBOL_PREFIX "bzero";
167 case BUILT_IN_MALLOC:
168 return CHKP_WRAPPER_SYMBOL_PREFIX "malloc";
169 case BUILT_IN_CALLOC:
170 return CHKP_WRAPPER_SYMBOL_PREFIX "calloc";
171 case BUILT_IN_REALLOC:
172 return CHKP_WRAPPER_SYMBOL_PREFIX "realloc";
174 default:
175 gcc_unreachable ();
178 return "";
181 /* Build a clone of FNDECL with a modified name. */
183 static tree
184 chkp_build_instrumented_fndecl (tree fndecl)
186 tree new_decl = copy_node (fndecl);
187 tree new_name;
188 std::string s;
190 /* called_as_built_in checks DECL_NAME to identify calls to
191 builtins. We want instrumented calls to builtins to be
192 recognized by called_as_built_in. Therefore use original
193 DECL_NAME for cloning with no prefixes. */
194 s = IDENTIFIER_POINTER (DECL_NAME (fndecl));
195 s += ".chkp";
196 DECL_NAME (new_decl) = get_identifier (s.c_str ());
198 /* References to the original and to the instrumented version
199 should look the same in the output assembly. And we cannot
200 use the same assembler name for the instrumented version
201 because it conflicts with decl merging algorithms in LTO.
202 Achieve the result by using transparent alias name for the
203 instrumented version. */
204 if (chkp_wrap_function(fndecl))
206 new_name = get_identifier (chkp_wrap_function_name (fndecl));
207 DECL_VISIBILITY (new_decl) = VISIBILITY_DEFAULT;
209 else
211 s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
212 s += ".chkp";
213 new_name = get_identifier (s.c_str ());
214 IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
215 TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
217 SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
219 /* For functions with body versioning will make a copy of arguments.
220 For functions with no body we need to do it here. */
221 if (!gimple_has_body_p (fndecl))
222 DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
224 /* We are going to modify attributes list and therefore should
225 make own copy. */
226 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
228 /* Change builtin function code. */
229 if (DECL_BUILT_IN (new_decl))
231 gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL);
232 gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS);
233 DECL_FUNCTION_CODE (new_decl)
234 = (enum built_in_function)(DECL_FUNCTION_CODE (new_decl)
235 + BEGIN_CHKP_BUILTINS + 1);
238 return new_decl;
242 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
243 Integer operands are replaced with values according to
244 INDEXES map having LEN elements. For operands out of len
245 we just add DELTA. */
247 static void
248 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
249 unsigned *indexes, int len, int delta)
251 tree attr = lookup_attribute (attr_name, attrs);
252 tree op;
254 if (!attr)
255 return;
257 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
258 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
260 int idx;
262 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
263 continue;
265 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
267 /* If idx exceeds indexes length then we just
268 keep it at the same distance from the last
269 known arg. */
270 if (idx > len)
271 idx += delta;
272 else
273 idx = indexes[idx - 1] + 1;
274 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
278 /* Make a copy of function type ORIG_TYPE adding pointer
279 bounds as additional arguments. */
281 tree
282 chkp_copy_function_type_adding_bounds (tree orig_type)
284 tree type;
285 tree arg_type, attrs;
286 unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
287 unsigned *indexes = XALLOCAVEC (unsigned, len);
288 unsigned idx = 0, new_idx = 0;
290 for (arg_type = TYPE_ARG_TYPES (orig_type);
291 arg_type;
292 arg_type = TREE_CHAIN (arg_type))
293 if (TREE_VALUE (arg_type) == void_type_node)
294 continue;
295 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
296 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
297 TREE_VALUE (arg_type), true)
298 || chkp_type_has_pointer (TREE_VALUE (arg_type)))
299 break;
301 /* We may use original type if there are no bounds passed. */
302 if (!arg_type)
303 return orig_type;
305 type = build_distinct_type_copy (orig_type);
306 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
308 for (arg_type = TYPE_ARG_TYPES (type);
309 arg_type;
310 arg_type = TREE_CHAIN (arg_type))
312 indexes[idx++] = new_idx++;
314 /* pass_by_reference returns 1 for void type,
315 so check for it first. */
316 if (TREE_VALUE (arg_type) == void_type_node)
317 continue;
318 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
319 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
320 TREE_VALUE (arg_type), true))
322 tree new_type = build_tree_list (NULL_TREE,
323 pointer_bounds_type_node);
324 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
325 TREE_CHAIN (arg_type) = new_type;
327 arg_type = TREE_CHAIN (arg_type);
328 new_idx++;
330 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
332 bitmap slots = BITMAP_ALLOC (NULL);
333 bitmap_iterator bi;
334 unsigned bnd_no;
336 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
338 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
340 tree new_type = build_tree_list (NULL_TREE,
341 pointer_bounds_type_node);
342 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
343 TREE_CHAIN (arg_type) = new_type;
345 arg_type = TREE_CHAIN (arg_type);
346 new_idx++;
348 BITMAP_FREE (slots);
352 /* If function type has attribute with arg indexes then
353 we have to copy it fixing attribute ops. Map for
354 fixing is in indexes array. */
355 attrs = TYPE_ATTRIBUTES (type);
356 if (lookup_attribute ("nonnull", attrs)
357 || lookup_attribute ("format", attrs)
358 || lookup_attribute ("format_arg", attrs))
360 int delta = new_idx - len;
361 attrs = copy_list (TYPE_ATTRIBUTES (type));
362 chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
363 chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
364 chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
365 TYPE_ATTRIBUTES (type) = attrs;
368 return type;
371 /* For given function FNDECL add bounds arguments to arguments
372 list. */
374 static void
375 chkp_add_bounds_params_to_function (tree fndecl)
377 tree arg;
379 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
380 if (BOUNDED_P (arg))
382 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
383 tree new_arg;
385 if (DECL_NAME (arg))
386 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
387 else
389 char uid[25];
390 snprintf (uid, 25, "D.%u", DECL_UID (arg));
391 new_name += uid;
394 new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
395 get_identifier (new_name.c_str ()),
396 pointer_bounds_type_node);
397 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
398 DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
399 DECL_ARTIFICIAL (new_arg) = 1;
400 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
401 DECL_CHAIN (arg) = new_arg;
403 arg = DECL_CHAIN (arg);
406 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
408 tree orig_arg = arg;
409 bitmap slots = BITMAP_ALLOC (NULL);
410 bitmap_iterator bi;
411 unsigned bnd_no;
413 chkp_find_bound_slots (TREE_TYPE (arg), slots);
415 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
417 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
418 tree new_arg;
419 char offs[25];
421 if (DECL_NAME (orig_arg))
422 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
423 else
425 snprintf (offs, 25, "D.%u", DECL_UID (arg));
426 new_name += offs;
428 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
430 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
431 PARM_DECL,
432 get_identifier (new_name.c_str ()),
433 pointer_bounds_type_node);
434 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
435 DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
436 DECL_ARTIFICIAL (new_arg) = 1;
437 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
438 DECL_CHAIN (arg) = new_arg;
440 arg = DECL_CHAIN (arg);
442 BITMAP_FREE (slots);
445 TREE_TYPE (fndecl) =
446 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
449 /* Return an instrumentation clone for builtin function
450 FNDECL. Create one if needed. */
452 tree
453 chkp_maybe_clone_builtin_fndecl (tree fndecl)
455 tree clone;
456 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
458 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
459 && fcode < BEGIN_CHKP_BUILTINS);
461 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
462 clone = builtin_decl_explicit (fcode);
463 if (clone)
464 return clone;
466 clone = chkp_build_instrumented_fndecl (fndecl);
467 chkp_add_bounds_params_to_function (clone);
469 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
471 set_builtin_decl (fcode, clone, false);
473 return clone;
476 /* Return 1 if function FNDECL should be instrumented. */
478 bool
479 chkp_instrumentable_p (tree fndecl)
481 struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
482 return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
483 && (!flag_chkp_instrument_marked_only
484 || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl)))
485 && (!fn || !copy_forbidden (fn, fndecl)));
488 /* Return clone created for instrumentation of NODE or NULL. */
490 cgraph_node *
491 chkp_maybe_create_clone (tree fndecl)
493 cgraph_node *node = cgraph_node::get_create (fndecl);
494 cgraph_node *clone = node->instrumented_version;
496 gcc_assert (!node->instrumentation_clone);
498 if (DECL_BUILT_IN (fndecl)
499 && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
500 || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
501 return NULL;
503 clone = node->instrumented_version;
505 /* Some instrumented builtin function calls may be optimized and
506 cgraph nodes may be removed as unreachable. Later optimizations
507 may generate new calls to removed functions and in this case
508 we have to recreate cgraph node. FUNCTION_DECL for instrumented
509 builtin still exists and should be reused in such case. */
510 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
511 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))
512 && !clone)
514 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
515 tree new_decl;
517 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
518 new_decl = builtin_decl_explicit (fncode);
520 /* We've actually already created an instrumented clone once.
521 Restore it. */
522 if (new_decl)
524 clone = cgraph_node::get (new_decl);
526 if (!clone)
528 gcc_assert (!gimple_has_body_p (fndecl));
529 clone = cgraph_node::get_create (new_decl);
530 clone->externally_visible = node->externally_visible;
531 clone->local = node->local;
532 clone->address_taken = node->address_taken;
533 clone->thunk = node->thunk;
534 clone->alias = node->alias;
535 clone->weakref = node->weakref;
536 clone->cpp_implicit_alias = node->cpp_implicit_alias;
537 clone->orig_decl = fndecl;
538 clone->instrumentation_clone = true;
541 clone->instrumented_version = node;
542 node->instrumented_version = clone;
546 if (!clone)
548 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
549 struct cgraph_edge *e;
550 struct ipa_ref *ref;
551 int i;
553 clone = node->create_version_clone (new_decl, vNULL, NULL);
554 clone->externally_visible = node->externally_visible;
555 clone->local = node->local;
556 clone->address_taken = node->address_taken;
557 clone->thunk = node->thunk;
558 clone->alias = node->alias;
559 clone->weakref = node->weakref;
560 clone->cpp_implicit_alias = node->cpp_implicit_alias;
561 clone->instrumented_version = node;
562 clone->orig_decl = fndecl;
563 clone->instrumentation_clone = true;
564 node->instrumented_version = clone;
566 if (gimple_has_body_p (fndecl))
568 /* If function will not be instrumented, then it's instrumented
569 version is a thunk for the original. */
570 if (!chkp_instrumentable_p (fndecl))
572 clone->remove_callees ();
573 clone->remove_all_references ();
574 clone->thunk.thunk_p = true;
575 clone->thunk.add_pointer_bounds_args = true;
576 clone->create_edge (node, NULL, 0, CGRAPH_FREQ_BASE);
577 /* Thunk shouldn't be a cdtor. */
578 DECL_STATIC_CONSTRUCTOR (clone->decl) = 0;
579 DECL_STATIC_DESTRUCTOR (clone->decl) = 0;
581 else
583 tree_function_versioning (fndecl, new_decl, NULL, false,
584 NULL, false, NULL, NULL);
585 clone->lowered = true;
589 /* New params are inserted after versioning because it
590 actually copies args list from the original decl. */
591 chkp_add_bounds_params_to_function (new_decl);
593 /* Remember builtin fndecl. */
594 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
595 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
597 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
598 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
599 clone->decl, false);
602 /* Clones have the same comdat group as originals. */
603 if (node->same_comdat_group
604 || (DECL_ONE_ONLY (node->decl)
605 && !DECL_EXTERNAL (node->decl)))
606 clone->add_to_same_comdat_group (node);
608 if (gimple_has_body_p (fndecl))
609 symtab->call_cgraph_insertion_hooks (clone);
611 /* Clone all aliases. */
612 for (i = 0; node->iterate_direct_aliases (i, ref); i++)
613 chkp_maybe_create_clone (ref->referring->decl);
615 /* Clone all thunks. */
616 for (e = node->callers; e; e = e->next_caller)
617 if (e->caller->thunk.thunk_p
618 && !e->caller->thunk.add_pointer_bounds_args
619 && !e->caller->instrumentation_clone)
621 struct cgraph_node *thunk
622 = chkp_maybe_create_clone (e->caller->decl);
623 /* Redirect thunk clone edge to the node clone. */
624 thunk->callees->redirect_callee (clone);
627 /* For aliases and thunks we should make sure target is cloned
628 to have proper references and edges. */
629 if (node->thunk.thunk_p)
630 chkp_maybe_create_clone (node->callees->callee->decl);
631 else if (node->alias)
633 struct cgraph_node *target;
635 ref = node->ref_list.first_reference ();
636 if (ref)
638 target = chkp_maybe_create_clone (ref->referred->decl);
639 clone->create_reference (target, IPA_REF_ALIAS);
642 if (node->alias_target)
644 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
646 target = chkp_maybe_create_clone (node->alias_target);
647 clone->alias_target = target->decl;
649 else
650 clone->alias_target = node->alias_target;
654 /* Add IPA reference. It's main role is to keep instrumented
655 version reachable while original node is reachable. */
656 ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
659 return clone;
662 /* Create clone for all functions to be instrumented. */
664 static unsigned int
665 chkp_versioning (void)
667 struct cgraph_node *node;
668 const char *reason;
670 bitmap_obstack_initialize (NULL);
672 FOR_EACH_DEFINED_FUNCTION (node)
674 if (!node->instrumentation_clone
675 && !node->instrumented_version
676 && !node->alias
677 && !node->thunk.thunk_p
678 && (!DECL_BUILT_IN (node->decl)
679 || (DECL_BUILT_IN_CLASS (node->decl) == BUILT_IN_NORMAL
680 && DECL_FUNCTION_CODE (node->decl) < BEGIN_CHKP_BUILTINS)))
682 if (chkp_instrumentable_p (node->decl))
683 chkp_maybe_create_clone (node->decl);
684 else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl),
685 node->decl)))
687 if (warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wchkp,
688 "function cannot be instrumented"))
689 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
694 /* Mark all aliases and thunks of functions with no instrumented
695 version as legacy function. */
696 FOR_EACH_DEFINED_FUNCTION (node)
698 if (!node->instrumentation_clone
699 && !node->instrumented_version
700 && (node->alias || node->thunk.thunk_p)
701 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
702 DECL_ATTRIBUTES (node->decl)
703 = tree_cons (get_identifier ("bnd_legacy"), NULL,
704 DECL_ATTRIBUTES (node->decl));
707 bitmap_obstack_release (NULL);
709 return 0;
712 /* In this pass we remove bodies of functions having
713 instrumented version. Functions with removed bodies
714 become a special kind of thunks to provide a connection
715 between calls to the original version and instrumented
716 function. */
718 static unsigned int
719 chkp_produce_thunks (bool early)
721 struct cgraph_node *node;
723 FOR_EACH_DEFINED_FUNCTION (node)
725 if (!node->instrumentation_clone
726 && node->instrumented_version
727 && gimple_has_body_p (node->decl)
728 && gimple_has_body_p (node->instrumented_version->decl)
729 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
730 || !early))
732 node->release_body ();
733 node->remove_callees ();
734 node->remove_all_references ();
736 node->thunk.thunk_p = true;
737 node->thunk.add_pointer_bounds_args = true;
738 node->create_edge (node->instrumented_version, NULL,
739 0, CGRAPH_FREQ_BASE);
740 node->create_reference (node->instrumented_version,
741 IPA_REF_CHKP, NULL);
742 /* Thunk shouldn't be a cdtor. */
743 DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
744 DECL_STATIC_DESTRUCTOR (node->decl) = 0;
748 /* Mark instrumentation clones created for aliases and thunks
749 as insttrumented so they could be removed as unreachable
750 now. */
751 if (!early)
753 FOR_EACH_DEFINED_FUNCTION (node)
755 if (node->instrumentation_clone
756 && (node->alias || node->thunk.thunk_p)
757 && !chkp_function_instrumented_p (node->decl))
758 chkp_function_mark_instrumented (node->decl);
762 return TODO_remove_functions;
765 const pass_data pass_data_ipa_chkp_versioning =
767 SIMPLE_IPA_PASS, /* type */
768 "chkp_versioning", /* name */
769 OPTGROUP_NONE, /* optinfo_flags */
770 TV_NONE, /* tv_id */
771 0, /* properties_required */
772 0, /* properties_provided */
773 0, /* properties_destroyed */
774 0, /* todo_flags_start */
775 0 /* todo_flags_finish */
778 const pass_data pass_data_ipa_chkp_early_produce_thunks =
780 SIMPLE_IPA_PASS, /* type */
781 "chkp_ecleanup", /* name */
782 OPTGROUP_NONE, /* optinfo_flags */
783 TV_NONE, /* tv_id */
784 0, /* properties_required */
785 0, /* properties_provided */
786 0, /* properties_destroyed */
787 0, /* todo_flags_start */
788 0 /* todo_flags_finish */
791 const pass_data pass_data_ipa_chkp_produce_thunks =
793 SIMPLE_IPA_PASS, /* type */
794 "chkp_cleanup", /* name */
795 OPTGROUP_NONE, /* optinfo_flags */
796 TV_NONE, /* tv_id */
797 0, /* properties_required */
798 0, /* properties_provided */
799 0, /* properties_destroyed */
800 0, /* todo_flags_start */
801 0 /* todo_flags_finish */
804 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
806 public:
807 pass_ipa_chkp_versioning (gcc::context *ctxt)
808 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
811 /* opt_pass methods: */
812 virtual opt_pass * clone ()
814 return new pass_ipa_chkp_versioning (m_ctxt);
817 virtual bool gate (function *)
819 return flag_check_pointer_bounds;
822 virtual unsigned int execute (function *)
824 return chkp_versioning ();
827 }; // class pass_ipa_chkp_versioning
829 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
831 public:
832 pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
833 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
836 /* opt_pass methods: */
837 virtual opt_pass * clone ()
839 return new pass_ipa_chkp_early_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 (true);
852 }; // class pass_chkp_produce_thunks
854 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
856 public:
857 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
858 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
861 /* opt_pass methods: */
862 virtual opt_pass * clone ()
864 return new pass_ipa_chkp_produce_thunks (m_ctxt);
867 virtual bool gate (function *)
869 return flag_check_pointer_bounds;
872 virtual unsigned int execute (function *)
874 return chkp_produce_thunks (false);
877 }; // class pass_chkp_produce_thunks
879 simple_ipa_opt_pass *
880 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
882 return new pass_ipa_chkp_versioning (ctxt);
885 simple_ipa_opt_pass *
886 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
888 return new pass_ipa_chkp_early_produce_thunks (ctxt);
891 simple_ipa_opt_pass *
892 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
894 return new pass_ipa_chkp_produce_thunks (ctxt);