2016-04-27 Hristian Kirtchev <kirtchev@adacore.com>
[official-gcc.git] / gcc / ipa-chkp.c
blob5f5df6483a79657a3b5d09fd066170e440b8c2dd
1 /* Pointer Bounds Checker IPA passes.
2 Copyright (C) 2014-2016 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 #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"
38 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
40 In instrumented code each pointer is provided with bounds. For input
41 pointer parameters it means we also have bounds passed. For calls it
42 means we have additional bounds arguments for pointer arguments.
44 To have all IPA optimizations working correctly we have to express
45 dataflow between passed and received bounds explicitly via additional
46 entries in function declaration arguments list and in function type.
47 Since we may have both instrumented and not instrumented code at the
48 same time, we cannot replace all original functions with their
49 instrumented variants. Therefore we create clones (versions) instead.
51 Instrumentation clones creation is a separate IPA pass which is a part
52 of early local passes. Clones are created after SSA is built (because
53 instrumentation pass works on SSA) and before any transformations
54 which may change pointer flow and therefore lead to incorrect code
55 instrumentation (possibly causing false bounds check failures).
57 Instrumentation clones have pointer bounds arguments added right after
58 pointer arguments. Clones have assembler name of the original
59 function with suffix added. New assembler name is in transparent
60 alias chain with the original name. Thus we expect all calls to the
61 original and instrumented functions look similar in assembler.
63 During instrumentation versioning pass we create instrumented versions
64 of all function with body and also for all their aliases and thunks.
65 Clones for functions with no body are created on demand (usually
66 during call instrumentation).
68 Original and instrumented function nodes are connected with IPA
69 reference IPA_REF_CHKP. It is mostly done to have reachability
70 analysis working correctly. We may have no references to the
71 instrumented function in the code but it still should be counted
72 as reachable if the original function is reachable.
74 When original function bodies are not needed anymore we release
75 them and transform functions into a special kind of thunks. Each
76 thunk has a call edge to the instrumented version. These thunks
77 help to keep externally visible instrumented functions visible
78 when linker resolution files are used. Linker has no info about
79 connection between original and instrumented function and
80 therefore we may wrongly decide (due to difference in assembler
81 names) that instrumented function version is local and can be
82 removed. */
84 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
85 #define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
87 /* Return 1 calls to FNDECL should be replaced with
88 a call to wrapper function. */
89 bool
90 chkp_wrap_function (tree fndecl)
92 if (!flag_chkp_use_wrappers)
93 return false;
95 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
97 switch (DECL_FUNCTION_CODE (fndecl))
99 case BUILT_IN_STRLEN:
100 case BUILT_IN_STRCPY:
101 case BUILT_IN_STRNCPY:
102 case BUILT_IN_STPCPY:
103 case BUILT_IN_STPNCPY:
104 case BUILT_IN_STRCAT:
105 case BUILT_IN_STRNCAT:
106 case BUILT_IN_MEMCPY:
107 case BUILT_IN_MEMPCPY:
108 case BUILT_IN_MEMSET:
109 case BUILT_IN_MEMMOVE:
110 case BUILT_IN_BZERO:
111 case BUILT_IN_MALLOC:
112 case BUILT_IN_CALLOC:
113 case BUILT_IN_REALLOC:
114 return 1;
116 default:
117 return 0;
121 return false;
124 static const char *
125 chkp_wrap_function_name (tree fndecl)
127 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL);
129 switch (DECL_FUNCTION_CODE (fndecl))
131 case BUILT_IN_STRLEN:
132 return CHKP_WRAPPER_SYMBOL_PREFIX "strlen";
133 case BUILT_IN_STRCPY:
134 return CHKP_WRAPPER_SYMBOL_PREFIX "strcpy";
135 case BUILT_IN_STRNCPY:
136 return CHKP_WRAPPER_SYMBOL_PREFIX "strncpy";
137 case BUILT_IN_STPCPY:
138 return CHKP_WRAPPER_SYMBOL_PREFIX "stpcpy";
139 case BUILT_IN_STPNCPY:
140 return CHKP_WRAPPER_SYMBOL_PREFIX "stpncpy";
141 case BUILT_IN_STRCAT:
142 return CHKP_WRAPPER_SYMBOL_PREFIX "strcat";
143 case BUILT_IN_STRNCAT:
144 return CHKP_WRAPPER_SYMBOL_PREFIX "strncat";
145 case BUILT_IN_MEMCPY:
146 return CHKP_WRAPPER_SYMBOL_PREFIX "memcpy";
147 case BUILT_IN_MEMPCPY:
148 return CHKP_WRAPPER_SYMBOL_PREFIX "mempcpy";
149 case BUILT_IN_MEMSET:
150 return CHKP_WRAPPER_SYMBOL_PREFIX "memset";
151 case BUILT_IN_MEMMOVE:
152 return CHKP_WRAPPER_SYMBOL_PREFIX "memmove";
153 case BUILT_IN_BZERO:
154 return CHKP_WRAPPER_SYMBOL_PREFIX "bzero";
155 case BUILT_IN_MALLOC:
156 return CHKP_WRAPPER_SYMBOL_PREFIX "malloc";
157 case BUILT_IN_CALLOC:
158 return CHKP_WRAPPER_SYMBOL_PREFIX "calloc";
159 case BUILT_IN_REALLOC:
160 return CHKP_WRAPPER_SYMBOL_PREFIX "realloc";
162 default:
163 gcc_unreachable ();
166 return "";
169 /* Build a clone of FNDECL with a modified name. */
171 static tree
172 chkp_build_instrumented_fndecl (tree fndecl)
174 tree new_decl = copy_node (fndecl);
175 tree new_name;
176 std::string s;
178 /* called_as_built_in checks DECL_NAME to identify calls to
179 builtins. We want instrumented calls to builtins to be
180 recognized by called_as_built_in. Therefore use original
181 DECL_NAME for cloning with no prefixes. */
182 s = IDENTIFIER_POINTER (DECL_NAME (fndecl));
183 s += ".chkp";
184 DECL_NAME (new_decl) = get_identifier (s.c_str ());
186 /* References to the original and to the instrumented version
187 should look the same in the output assembly. And we cannot
188 use the same assembler name for the instrumented version
189 because it conflicts with decl merging algorithms in LTO.
190 Achieve the result by using transparent alias name for the
191 instrumented version. */
192 if (chkp_wrap_function(fndecl))
194 new_name = get_identifier (chkp_wrap_function_name (fndecl));
195 DECL_VISIBILITY (new_decl) = VISIBILITY_DEFAULT;
197 else
199 s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
200 s += ".chkp";
201 new_name = get_identifier (s.c_str ());
202 IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
203 TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
205 SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
207 /* For functions with body versioning will make a copy of arguments.
208 For functions with no body we need to do it here. */
209 if (!gimple_has_body_p (fndecl))
210 DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
212 /* We are going to modify attributes list and therefore should
213 make own copy. */
214 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
216 /* Change builtin function code. */
217 if (DECL_BUILT_IN (new_decl))
219 gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL);
220 gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS);
221 DECL_FUNCTION_CODE (new_decl)
222 = (enum built_in_function)(DECL_FUNCTION_CODE (new_decl)
223 + BEGIN_CHKP_BUILTINS + 1);
226 return new_decl;
230 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
231 Integer operands are replaced with values according to
232 INDEXES map having LEN elements. For operands out of len
233 we just add DELTA. */
235 static void
236 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
237 unsigned *indexes, int len, int delta)
239 tree attr = lookup_attribute (attr_name, attrs);
240 tree op;
242 if (!attr)
243 return;
245 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
246 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
248 int idx;
250 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
251 continue;
253 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
255 /* If idx exceeds indexes length then we just
256 keep it at the same distance from the last
257 known arg. */
258 if (idx > len)
259 idx += delta;
260 else
261 idx = indexes[idx - 1] + 1;
262 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
266 /* Make a copy of function type ORIG_TYPE adding pointer
267 bounds as additional arguments. */
269 tree
270 chkp_copy_function_type_adding_bounds (tree orig_type)
272 tree type;
273 tree arg_type, attrs;
274 unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
275 unsigned *indexes = XALLOCAVEC (unsigned, len);
276 unsigned idx = 0, new_idx = 0;
278 for (arg_type = TYPE_ARG_TYPES (orig_type);
279 arg_type;
280 arg_type = TREE_CHAIN (arg_type))
281 if (TREE_VALUE (arg_type) == void_type_node)
282 continue;
283 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
284 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
285 TREE_VALUE (arg_type), true)
286 || chkp_type_has_pointer (TREE_VALUE (arg_type)))
287 break;
289 /* We may use original type if there are no bounds passed. */
290 if (!arg_type)
291 return orig_type;
293 type = build_distinct_type_copy (orig_type);
294 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
296 for (arg_type = TYPE_ARG_TYPES (type);
297 arg_type;
298 arg_type = TREE_CHAIN (arg_type))
300 indexes[idx++] = new_idx++;
302 /* pass_by_reference returns 1 for void type,
303 so check for it first. */
304 if (TREE_VALUE (arg_type) == void_type_node)
305 continue;
306 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
307 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
308 TREE_VALUE (arg_type), true))
310 tree new_type = build_tree_list (NULL_TREE,
311 pointer_bounds_type_node);
312 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
313 TREE_CHAIN (arg_type) = new_type;
315 arg_type = TREE_CHAIN (arg_type);
316 new_idx++;
318 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
320 bitmap slots = BITMAP_ALLOC (NULL);
321 bitmap_iterator bi;
322 unsigned bnd_no;
324 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
326 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
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;
333 arg_type = TREE_CHAIN (arg_type);
334 new_idx++;
336 BITMAP_FREE (slots);
340 /* If function type has attribute with arg indexes then
341 we have to copy it fixing attribute ops. Map for
342 fixing is in indexes array. */
343 attrs = TYPE_ATTRIBUTES (type);
344 if (lookup_attribute ("nonnull", attrs)
345 || lookup_attribute ("format", attrs)
346 || lookup_attribute ("format_arg", attrs))
348 int delta = new_idx - len;
349 attrs = copy_list (TYPE_ATTRIBUTES (type));
350 chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
351 chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
352 chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
353 TYPE_ATTRIBUTES (type) = attrs;
356 return type;
359 /* For given function FNDECL add bounds arguments to arguments
360 list. */
362 static void
363 chkp_add_bounds_params_to_function (tree fndecl)
365 tree arg;
367 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
368 if (BOUNDED_P (arg))
370 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
371 tree new_arg;
373 if (DECL_NAME (arg))
374 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
375 else
377 char uid[25];
378 snprintf (uid, 25, "D.%u", DECL_UID (arg));
379 new_name += uid;
382 new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
383 get_identifier (new_name.c_str ()),
384 pointer_bounds_type_node);
385 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
386 DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
387 DECL_ARTIFICIAL (new_arg) = 1;
388 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
389 DECL_CHAIN (arg) = new_arg;
391 arg = DECL_CHAIN (arg);
394 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
396 tree orig_arg = arg;
397 bitmap slots = BITMAP_ALLOC (NULL);
398 bitmap_iterator bi;
399 unsigned bnd_no;
401 chkp_find_bound_slots (TREE_TYPE (arg), slots);
403 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
405 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
406 tree new_arg;
407 char offs[25];
409 if (DECL_NAME (orig_arg))
410 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
411 else
413 snprintf (offs, 25, "D.%u", DECL_UID (arg));
414 new_name += offs;
416 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
418 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
419 PARM_DECL,
420 get_identifier (new_name.c_str ()),
421 pointer_bounds_type_node);
422 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
423 DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
424 DECL_ARTIFICIAL (new_arg) = 1;
425 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
426 DECL_CHAIN (arg) = new_arg;
428 arg = DECL_CHAIN (arg);
430 BITMAP_FREE (slots);
433 TREE_TYPE (fndecl) =
434 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
437 /* Return an instrumentation clone for builtin function
438 FNDECL. Create one if needed. */
440 tree
441 chkp_maybe_clone_builtin_fndecl (tree fndecl)
443 tree clone;
444 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
446 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
447 && fcode < BEGIN_CHKP_BUILTINS);
449 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
450 clone = builtin_decl_explicit (fcode);
451 if (clone)
452 return clone;
454 clone = chkp_build_instrumented_fndecl (fndecl);
455 chkp_add_bounds_params_to_function (clone);
457 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
459 set_builtin_decl (fcode, clone, false);
461 return clone;
464 /* Return 1 if function FNDECL should be instrumented. */
466 bool
467 chkp_instrumentable_p (tree fndecl)
469 struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
470 return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
471 && (!flag_chkp_instrument_marked_only
472 || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl)))
473 && (!fn || !copy_forbidden (fn)));
476 /* Return clone created for instrumentation of NODE or NULL. */
478 cgraph_node *
479 chkp_maybe_create_clone (tree fndecl)
481 cgraph_node *node = cgraph_node::get_create (fndecl);
482 cgraph_node *clone = node->instrumented_version;
484 gcc_assert (!node->instrumentation_clone);
486 if (DECL_BUILT_IN (fndecl)
487 && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
488 || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
489 return NULL;
491 clone = node->instrumented_version;
493 /* Some instrumented builtin function calls may be optimized and
494 cgraph nodes may be removed as unreachable. Later optimizations
495 may generate new calls to removed functions and in this case
496 we have to recreate cgraph node. FUNCTION_DECL for instrumented
497 builtin still exists and should be reused in such case. */
498 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
499 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))
500 && !clone)
502 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
503 tree new_decl;
505 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
506 new_decl = builtin_decl_explicit (fncode);
508 /* We've actually already created an instrumented clone once.
509 Restore it. */
510 if (new_decl)
512 clone = cgraph_node::get (new_decl);
514 if (!clone)
516 gcc_assert (!gimple_has_body_p (fndecl));
517 clone = cgraph_node::get_create (new_decl);
518 clone->externally_visible = node->externally_visible;
519 clone->local = node->local;
520 clone->address_taken = node->address_taken;
521 clone->thunk = node->thunk;
522 clone->alias = node->alias;
523 clone->weakref = node->weakref;
524 clone->cpp_implicit_alias = node->cpp_implicit_alias;
525 clone->orig_decl = fndecl;
526 clone->instrumentation_clone = true;
529 clone->instrumented_version = node;
530 node->instrumented_version = clone;
534 if (!clone)
536 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
537 struct cgraph_edge *e;
538 struct ipa_ref *ref;
539 int i;
541 clone = node->create_version_clone (new_decl, vNULL, NULL);
542 clone->externally_visible = node->externally_visible;
543 clone->local = node->local;
544 clone->address_taken = node->address_taken;
545 clone->thunk = node->thunk;
546 clone->alias = node->alias;
547 clone->weakref = node->weakref;
548 clone->cpp_implicit_alias = node->cpp_implicit_alias;
549 clone->instrumented_version = node;
550 clone->orig_decl = fndecl;
551 clone->instrumentation_clone = true;
552 node->instrumented_version = clone;
554 if (gimple_has_body_p (fndecl))
556 gcc_assert (chkp_instrumentable_p (fndecl));
557 tree_function_versioning (fndecl, new_decl, NULL, false,
558 NULL, false, NULL, NULL);
559 clone->lowered = true;
562 /* New params are inserted after versioning because it
563 actually copies args list from the original decl. */
564 chkp_add_bounds_params_to_function (new_decl);
566 /* Remember builtin fndecl. */
567 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
568 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
570 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
571 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
572 clone->decl, false);
575 /* Clones have the same comdat group as originals. */
576 if (node->same_comdat_group
577 || (DECL_ONE_ONLY (node->decl)
578 && !DECL_EXTERNAL (node->decl)))
579 clone->add_to_same_comdat_group (node);
581 if (gimple_has_body_p (fndecl))
582 symtab->call_cgraph_insertion_hooks (clone);
584 /* Clone all aliases. */
585 for (i = 0; node->iterate_direct_aliases (i, ref); i++)
586 chkp_maybe_create_clone (ref->referring->decl);
588 /* Clone all thunks. */
589 for (e = node->callers; e; e = e->next_caller)
590 if (e->caller->thunk.thunk_p
591 && !e->caller->thunk.add_pointer_bounds_args
592 && !e->caller->instrumentation_clone)
594 struct cgraph_node *thunk
595 = chkp_maybe_create_clone (e->caller->decl);
596 /* Redirect thunk clone edge to the node clone. */
597 thunk->callees->redirect_callee (clone);
600 /* For aliases and thunks we should make sure target is cloned
601 to have proper references and edges. */
602 if (node->thunk.thunk_p)
603 chkp_maybe_create_clone (node->callees->callee->decl);
604 else if (node->alias)
606 struct cgraph_node *target;
608 ref = node->ref_list.first_reference ();
609 if (ref)
611 target = chkp_maybe_create_clone (ref->referred->decl);
612 clone->create_reference (target, IPA_REF_ALIAS);
615 if (node->alias_target)
617 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
619 target = chkp_maybe_create_clone (node->alias_target);
620 clone->alias_target = target->decl;
622 else
623 clone->alias_target = node->alias_target;
627 /* Add IPA reference. It's main role is to keep instrumented
628 version reachable while original node is reachable. */
629 ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
632 return clone;
635 /* Create clone for all functions to be instrumented. */
637 static unsigned int
638 chkp_versioning (void)
640 struct cgraph_node *node;
641 const char *reason;
643 bitmap_obstack_initialize (NULL);
645 FOR_EACH_DEFINED_FUNCTION (node)
647 tree decl = node->decl;
648 if (!node->instrumentation_clone
649 && !node->instrumented_version
650 && !node->alias
651 && !node->thunk.thunk_p
652 && (!DECL_BUILT_IN (decl)
653 || (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
654 && DECL_FUNCTION_CODE (decl) < BEGIN_CHKP_BUILTINS)))
656 if (chkp_instrumentable_p (decl))
657 chkp_maybe_create_clone (decl);
658 else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (decl))))
660 if (warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wchkp,
661 "function cannot be instrumented"))
662 inform (DECL_SOURCE_LOCATION (decl), reason, decl);
667 /* Mark all aliases and thunks of functions with no instrumented
668 version as legacy function. */
669 FOR_EACH_DEFINED_FUNCTION (node)
671 if (!node->instrumentation_clone
672 && !node->instrumented_version
673 && (node->alias || node->thunk.thunk_p)
674 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
675 DECL_ATTRIBUTES (node->decl)
676 = tree_cons (get_identifier ("bnd_legacy"), NULL,
677 DECL_ATTRIBUTES (node->decl));
680 bitmap_obstack_release (NULL);
682 return 0;
685 /* In this pass we remove bodies of functions having
686 instrumented version. Functions with removed bodies
687 become a special kind of thunks to provide a connection
688 between calls to the original version and instrumented
689 function. */
691 static unsigned int
692 chkp_produce_thunks (bool early)
694 struct cgraph_node *node;
696 FOR_EACH_DEFINED_FUNCTION (node)
698 if (!node->instrumentation_clone
699 && node->instrumented_version
700 && gimple_has_body_p (node->decl)
701 && gimple_has_body_p (node->instrumented_version->decl)
702 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
703 || !early))
705 node->release_body ();
706 node->remove_callees ();
707 node->remove_all_references ();
709 node->thunk.thunk_p = true;
710 node->thunk.add_pointer_bounds_args = true;
711 node->create_edge (node->instrumented_version, NULL,
712 0, CGRAPH_FREQ_BASE);
713 node->create_reference (node->instrumented_version,
714 IPA_REF_CHKP, NULL);
715 /* Thunk shouldn't be a cdtor. */
716 DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
717 DECL_STATIC_DESTRUCTOR (node->decl) = 0;
721 /* Mark instrumentation clones created for aliases and thunks
722 as insttrumented so they could be removed as unreachable
723 now. */
724 if (!early)
726 FOR_EACH_DEFINED_FUNCTION (node)
728 if (node->instrumentation_clone
729 && (node->alias || node->thunk.thunk_p)
730 && !chkp_function_instrumented_p (node->decl))
731 chkp_function_mark_instrumented (node->decl);
735 return TODO_remove_functions;
738 const pass_data pass_data_ipa_chkp_versioning =
740 SIMPLE_IPA_PASS, /* type */
741 "chkp_versioning", /* name */
742 OPTGROUP_NONE, /* optinfo_flags */
743 TV_NONE, /* tv_id */
744 0, /* properties_required */
745 0, /* properties_provided */
746 0, /* properties_destroyed */
747 0, /* todo_flags_start */
748 0 /* todo_flags_finish */
751 const pass_data pass_data_ipa_chkp_early_produce_thunks =
753 SIMPLE_IPA_PASS, /* type */
754 "chkp_ecleanup", /* name */
755 OPTGROUP_NONE, /* optinfo_flags */
756 TV_NONE, /* tv_id */
757 0, /* properties_required */
758 0, /* properties_provided */
759 0, /* properties_destroyed */
760 0, /* todo_flags_start */
761 0 /* todo_flags_finish */
764 const pass_data pass_data_ipa_chkp_produce_thunks =
766 SIMPLE_IPA_PASS, /* type */
767 "chkp_cleanup", /* name */
768 OPTGROUP_NONE, /* optinfo_flags */
769 TV_NONE, /* tv_id */
770 0, /* properties_required */
771 0, /* properties_provided */
772 0, /* properties_destroyed */
773 0, /* todo_flags_start */
774 0 /* todo_flags_finish */
777 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
779 public:
780 pass_ipa_chkp_versioning (gcc::context *ctxt)
781 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
784 /* opt_pass methods: */
785 virtual opt_pass * clone ()
787 return new pass_ipa_chkp_versioning (m_ctxt);
790 virtual bool gate (function *)
792 return flag_check_pointer_bounds;
795 virtual unsigned int execute (function *)
797 return chkp_versioning ();
800 }; // class pass_ipa_chkp_versioning
802 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
804 public:
805 pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
806 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
809 /* opt_pass methods: */
810 virtual opt_pass * clone ()
812 return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
815 virtual bool gate (function *)
817 return flag_check_pointer_bounds;
820 virtual unsigned int execute (function *)
822 return chkp_produce_thunks (true);
825 }; // class pass_chkp_produce_thunks
827 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
829 public:
830 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
831 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
834 /* opt_pass methods: */
835 virtual opt_pass * clone ()
837 return new pass_ipa_chkp_produce_thunks (m_ctxt);
840 virtual bool gate (function *)
842 return flag_check_pointer_bounds;
845 virtual unsigned int execute (function *)
847 return chkp_produce_thunks (false);
850 }; // class pass_chkp_produce_thunks
852 simple_ipa_opt_pass *
853 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
855 return new pass_ipa_chkp_versioning (ctxt);
858 simple_ipa_opt_pass *
859 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
861 return new pass_ipa_chkp_early_produce_thunks (ctxt);
864 simple_ipa_opt_pass *
865 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
867 return new pass_ipa_chkp_produce_thunks (ctxt);