2016-01-21 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / gcc / ipa-chkp.c
blob183e7ce161ea94ea179d4b5b1d6ff0874e0e1418
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 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "tree.h"
26 #include "gimple.h"
27 #include "tree-pass.h"
28 #include "stringpool.h"
29 #include "lto-streamer.h"
30 #include "stor-layout.h"
31 #include "calls.h"
32 #include "cgraph.h"
33 #include "tree-chkp.h"
34 #include "tree-inline.h"
35 #include "ipa-chkp.h"
37 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
39 In instrumented code each pointer is provided with bounds. For input
40 pointer parameters it means we also have bounds passed. For calls it
41 means we have additional bounds arguments for pointer arguments.
43 To have all IPA optimizations working correctly we have to express
44 dataflow between passed and received bounds explicitly via additional
45 entries in function declaration arguments list and in function type.
46 Since we may have both instrumented and not instrumented code at the
47 same time, we cannot replace all original functions with their
48 instrumented variants. Therefore we create clones (versions) instead.
50 Instrumentation clones creation is a separate IPA pass which is a part
51 of early local passes. Clones are created after SSA is built (because
52 instrumentation pass works on SSA) and before any transformations
53 which may change pointer flow and therefore lead to incorrect code
54 instrumentation (possibly causing false bounds check failures).
56 Instrumentation clones have pointer bounds arguments added right after
57 pointer arguments. Clones have assembler name of the original
58 function with suffix added. New assembler name is in transparent
59 alias chain with the original name. Thus we expect all calls to the
60 original and instrumented functions look similar in assembler.
62 During instrumentation versioning pass we create instrumented versions
63 of all function with body and also for all their aliases and thunks.
64 Clones for functions with no body are created on demand (usually
65 during call instrumentation).
67 Original and instrumented function nodes are connected with IPA
68 reference IPA_REF_CHKP. It is mostly done to have reachability
69 analysis working correctly. We may have no references to the
70 instrumented function in the code but it still should be counted
71 as reachable if the original function is reachable.
73 When original function bodies are not needed anymore we release
74 them and transform functions into a special kind of thunks. Each
75 thunk has a call edge to the instrumented version. These thunks
76 help to keep externally visible instrumented functions visible
77 when linker resolution files are used. Linker has no info about
78 connection between original and instrumented function and
79 therefore we may wrongly decide (due to difference in assembler
80 names) that instrumented function version is local and can be
81 removed. */
83 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
84 #define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
86 /* Return 1 calls to FNDECL should be replaced with
87 a call to wrapper function. */
88 bool
89 chkp_wrap_function (tree fndecl)
91 if (!flag_chkp_use_wrappers)
92 return false;
94 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
96 switch (DECL_FUNCTION_CODE (fndecl))
98 case BUILT_IN_STRLEN:
99 case BUILT_IN_STRCPY:
100 case BUILT_IN_STRNCPY:
101 case BUILT_IN_STPCPY:
102 case BUILT_IN_STPNCPY:
103 case BUILT_IN_STRCAT:
104 case BUILT_IN_STRNCAT:
105 case BUILT_IN_MEMCPY:
106 case BUILT_IN_MEMPCPY:
107 case BUILT_IN_MEMSET:
108 case BUILT_IN_MEMMOVE:
109 case BUILT_IN_BZERO:
110 case BUILT_IN_MALLOC:
111 case BUILT_IN_CALLOC:
112 case BUILT_IN_REALLOC:
113 return 1;
115 default:
116 return 0;
120 return false;
123 static const char *
124 chkp_wrap_function_name (tree fndecl)
126 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL);
128 switch (DECL_FUNCTION_CODE (fndecl))
130 case BUILT_IN_STRLEN:
131 return CHKP_WRAPPER_SYMBOL_PREFIX "strlen";
132 case BUILT_IN_STRCPY:
133 return CHKP_WRAPPER_SYMBOL_PREFIX "strcpy";
134 case BUILT_IN_STRNCPY:
135 return CHKP_WRAPPER_SYMBOL_PREFIX "strncpy";
136 case BUILT_IN_STPCPY:
137 return CHKP_WRAPPER_SYMBOL_PREFIX "stpcpy";
138 case BUILT_IN_STPNCPY:
139 return CHKP_WRAPPER_SYMBOL_PREFIX "stpncpy";
140 case BUILT_IN_STRCAT:
141 return CHKP_WRAPPER_SYMBOL_PREFIX "strcat";
142 case BUILT_IN_STRNCAT:
143 return CHKP_WRAPPER_SYMBOL_PREFIX "strncat";
144 case BUILT_IN_MEMCPY:
145 return CHKP_WRAPPER_SYMBOL_PREFIX "memcpy";
146 case BUILT_IN_MEMPCPY:
147 return CHKP_WRAPPER_SYMBOL_PREFIX "mempcpy";
148 case BUILT_IN_MEMSET:
149 return CHKP_WRAPPER_SYMBOL_PREFIX "memset";
150 case BUILT_IN_MEMMOVE:
151 return CHKP_WRAPPER_SYMBOL_PREFIX "memmove";
152 case BUILT_IN_BZERO:
153 return CHKP_WRAPPER_SYMBOL_PREFIX "bzero";
154 case BUILT_IN_MALLOC:
155 return CHKP_WRAPPER_SYMBOL_PREFIX "malloc";
156 case BUILT_IN_CALLOC:
157 return CHKP_WRAPPER_SYMBOL_PREFIX "calloc";
158 case BUILT_IN_REALLOC:
159 return CHKP_WRAPPER_SYMBOL_PREFIX "realloc";
161 default:
162 gcc_unreachable ();
165 return "";
168 /* Build a clone of FNDECL with a modified name. */
170 static tree
171 chkp_build_instrumented_fndecl (tree fndecl)
173 tree new_decl = copy_node (fndecl);
174 tree new_name;
175 std::string s;
177 /* called_as_built_in checks DECL_NAME to identify calls to
178 builtins. We want instrumented calls to builtins to be
179 recognized by called_as_built_in. Therefore use original
180 DECL_NAME for cloning with no prefixes. */
181 s = IDENTIFIER_POINTER (DECL_NAME (fndecl));
182 s += ".chkp";
183 DECL_NAME (new_decl) = get_identifier (s.c_str ());
185 /* References to the original and to the instrumented version
186 should look the same in the output assembly. And we cannot
187 use the same assembler name for the instrumented version
188 because it conflicts with decl merging algorithms in LTO.
189 Achieve the result by using transparent alias name for the
190 instrumented version. */
191 if (chkp_wrap_function(fndecl))
193 new_name = get_identifier (chkp_wrap_function_name (fndecl));
194 DECL_VISIBILITY (new_decl) = VISIBILITY_DEFAULT;
196 else
198 s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
199 s += ".chkp";
200 new_name = get_identifier (s.c_str ());
201 IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
202 TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
204 SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
206 /* For functions with body versioning will make a copy of arguments.
207 For functions with no body we need to do it here. */
208 if (!gimple_has_body_p (fndecl))
209 DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
211 /* We are going to modify attributes list and therefore should
212 make own copy. */
213 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
215 /* Change builtin function code. */
216 if (DECL_BUILT_IN (new_decl))
218 gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL);
219 gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS);
220 DECL_FUNCTION_CODE (new_decl)
221 = (enum built_in_function)(DECL_FUNCTION_CODE (new_decl)
222 + BEGIN_CHKP_BUILTINS + 1);
225 return new_decl;
229 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
230 Integer operands are replaced with values according to
231 INDEXES map having LEN elements. For operands out of len
232 we just add DELTA. */
234 static void
235 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
236 unsigned *indexes, int len, int delta)
238 tree attr = lookup_attribute (attr_name, attrs);
239 tree op;
241 if (!attr)
242 return;
244 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
245 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
247 int idx;
249 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
250 continue;
252 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
254 /* If idx exceeds indexes length then we just
255 keep it at the same distance from the last
256 known arg. */
257 if (idx > len)
258 idx += delta;
259 else
260 idx = indexes[idx - 1] + 1;
261 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
265 /* Make a copy of function type ORIG_TYPE adding pointer
266 bounds as additional arguments. */
268 tree
269 chkp_copy_function_type_adding_bounds (tree orig_type)
271 tree type;
272 tree arg_type, attrs;
273 unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
274 unsigned *indexes = XALLOCAVEC (unsigned, len);
275 unsigned idx = 0, new_idx = 0;
277 for (arg_type = TYPE_ARG_TYPES (orig_type);
278 arg_type;
279 arg_type = TREE_CHAIN (arg_type))
280 if (TREE_VALUE (arg_type) == void_type_node)
281 continue;
282 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
283 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
284 TREE_VALUE (arg_type), true)
285 || chkp_type_has_pointer (TREE_VALUE (arg_type)))
286 break;
288 /* We may use original type if there are no bounds passed. */
289 if (!arg_type)
290 return orig_type;
292 type = build_distinct_type_copy (orig_type);
293 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
295 for (arg_type = TYPE_ARG_TYPES (type);
296 arg_type;
297 arg_type = TREE_CHAIN (arg_type))
299 indexes[idx++] = new_idx++;
301 /* pass_by_reference returns 1 for void type,
302 so check for it first. */
303 if (TREE_VALUE (arg_type) == void_type_node)
304 continue;
305 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
306 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
307 TREE_VALUE (arg_type), true))
309 tree new_type = build_tree_list (NULL_TREE,
310 pointer_bounds_type_node);
311 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
312 TREE_CHAIN (arg_type) = new_type;
314 arg_type = TREE_CHAIN (arg_type);
315 new_idx++;
317 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
319 bitmap slots = BITMAP_ALLOC (NULL);
320 bitmap_iterator bi;
321 unsigned bnd_no;
323 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
325 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
327 tree new_type = build_tree_list (NULL_TREE,
328 pointer_bounds_type_node);
329 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
330 TREE_CHAIN (arg_type) = new_type;
332 arg_type = TREE_CHAIN (arg_type);
333 new_idx++;
335 BITMAP_FREE (slots);
339 /* If function type has attribute with arg indexes then
340 we have to copy it fixing attribute ops. Map for
341 fixing is in indexes array. */
342 attrs = TYPE_ATTRIBUTES (type);
343 if (lookup_attribute ("nonnull", attrs)
344 || lookup_attribute ("format", attrs)
345 || lookup_attribute ("format_arg", attrs))
347 int delta = new_idx - len;
348 attrs = copy_list (TYPE_ATTRIBUTES (type));
349 chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
350 chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
351 chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
352 TYPE_ATTRIBUTES (type) = attrs;
355 return type;
358 /* For given function FNDECL add bounds arguments to arguments
359 list. */
361 static void
362 chkp_add_bounds_params_to_function (tree fndecl)
364 tree arg;
366 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
367 if (BOUNDED_P (arg))
369 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
370 tree new_arg;
372 if (DECL_NAME (arg))
373 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
374 else
376 char uid[25];
377 snprintf (uid, 25, "D.%u", DECL_UID (arg));
378 new_name += uid;
381 new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
382 get_identifier (new_name.c_str ()),
383 pointer_bounds_type_node);
384 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
385 DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
386 DECL_ARTIFICIAL (new_arg) = 1;
387 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
388 DECL_CHAIN (arg) = new_arg;
390 arg = DECL_CHAIN (arg);
393 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
395 tree orig_arg = arg;
396 bitmap slots = BITMAP_ALLOC (NULL);
397 bitmap_iterator bi;
398 unsigned bnd_no;
400 chkp_find_bound_slots (TREE_TYPE (arg), slots);
402 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
404 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
405 tree new_arg;
406 char offs[25];
408 if (DECL_NAME (orig_arg))
409 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
410 else
412 snprintf (offs, 25, "D.%u", DECL_UID (arg));
413 new_name += offs;
415 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
417 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
418 PARM_DECL,
419 get_identifier (new_name.c_str ()),
420 pointer_bounds_type_node);
421 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
422 DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
423 DECL_ARTIFICIAL (new_arg) = 1;
424 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
425 DECL_CHAIN (arg) = new_arg;
427 arg = DECL_CHAIN (arg);
429 BITMAP_FREE (slots);
432 TREE_TYPE (fndecl) =
433 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
436 /* Return an instrumentation clone for builtin function
437 FNDECL. Create one if needed. */
439 tree
440 chkp_maybe_clone_builtin_fndecl (tree fndecl)
442 tree clone;
443 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
445 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
446 && fcode < BEGIN_CHKP_BUILTINS);
448 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
449 clone = builtin_decl_explicit (fcode);
450 if (clone)
451 return clone;
453 clone = chkp_build_instrumented_fndecl (fndecl);
454 chkp_add_bounds_params_to_function (clone);
456 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
458 set_builtin_decl (fcode, clone, false);
460 return clone;
463 /* Return 1 if function FNDECL should be instrumented. */
465 bool
466 chkp_instrumentable_p (tree fndecl)
468 struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
469 return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
470 && (!flag_chkp_instrument_marked_only
471 || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl)))
472 && (!fn || !copy_forbidden (fn, fndecl)));
475 /* Return clone created for instrumentation of NODE or NULL. */
477 cgraph_node *
478 chkp_maybe_create_clone (tree fndecl)
480 cgraph_node *node = cgraph_node::get_create (fndecl);
481 cgraph_node *clone = node->instrumented_version;
483 gcc_assert (!node->instrumentation_clone);
485 if (DECL_BUILT_IN (fndecl)
486 && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
487 || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
488 return NULL;
490 clone = node->instrumented_version;
492 /* Some instrumented builtin function calls may be optimized and
493 cgraph nodes may be removed as unreachable. Later optimizations
494 may generate new calls to removed functions and in this case
495 we have to recreate cgraph node. FUNCTION_DECL for instrumented
496 builtin still exists and should be reused in such case. */
497 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
498 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))
499 && !clone)
501 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
502 tree new_decl;
504 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
505 new_decl = builtin_decl_explicit (fncode);
507 /* We've actually already created an instrumented clone once.
508 Restore it. */
509 if (new_decl)
511 clone = cgraph_node::get (new_decl);
513 if (!clone)
515 gcc_assert (!gimple_has_body_p (fndecl));
516 clone = cgraph_node::get_create (new_decl);
517 clone->externally_visible = node->externally_visible;
518 clone->local = node->local;
519 clone->address_taken = node->address_taken;
520 clone->thunk = node->thunk;
521 clone->alias = node->alias;
522 clone->weakref = node->weakref;
523 clone->cpp_implicit_alias = node->cpp_implicit_alias;
524 clone->orig_decl = fndecl;
525 clone->instrumentation_clone = true;
528 clone->instrumented_version = node;
529 node->instrumented_version = clone;
533 if (!clone)
535 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
536 struct cgraph_edge *e;
537 struct ipa_ref *ref;
538 int i;
540 clone = node->create_version_clone (new_decl, vNULL, NULL);
541 clone->externally_visible = node->externally_visible;
542 clone->local = node->local;
543 clone->address_taken = node->address_taken;
544 clone->thunk = node->thunk;
545 clone->alias = node->alias;
546 clone->weakref = node->weakref;
547 clone->cpp_implicit_alias = node->cpp_implicit_alias;
548 clone->instrumented_version = node;
549 clone->orig_decl = fndecl;
550 clone->instrumentation_clone = true;
551 node->instrumented_version = clone;
553 if (gimple_has_body_p (fndecl))
555 gcc_assert (chkp_instrumentable_p (fndecl));
556 tree_function_versioning (fndecl, new_decl, NULL, false,
557 NULL, false, NULL, NULL);
558 clone->lowered = true;
561 /* New params are inserted after versioning because it
562 actually copies args list from the original decl. */
563 chkp_add_bounds_params_to_function (new_decl);
565 /* Remember builtin fndecl. */
566 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
567 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
569 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
570 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
571 clone->decl, false);
574 /* Clones have the same comdat group as originals. */
575 if (node->same_comdat_group
576 || (DECL_ONE_ONLY (node->decl)
577 && !DECL_EXTERNAL (node->decl)))
578 clone->add_to_same_comdat_group (node);
580 if (gimple_has_body_p (fndecl))
581 symtab->call_cgraph_insertion_hooks (clone);
583 /* Clone all aliases. */
584 for (i = 0; node->iterate_direct_aliases (i, ref); i++)
585 chkp_maybe_create_clone (ref->referring->decl);
587 /* Clone all thunks. */
588 for (e = node->callers; e; e = e->next_caller)
589 if (e->caller->thunk.thunk_p
590 && !e->caller->thunk.add_pointer_bounds_args
591 && !e->caller->instrumentation_clone)
593 struct cgraph_node *thunk
594 = chkp_maybe_create_clone (e->caller->decl);
595 /* Redirect thunk clone edge to the node clone. */
596 thunk->callees->redirect_callee (clone);
599 /* For aliases and thunks we should make sure target is cloned
600 to have proper references and edges. */
601 if (node->thunk.thunk_p)
602 chkp_maybe_create_clone (node->callees->callee->decl);
603 else if (node->alias)
605 struct cgraph_node *target;
607 ref = node->ref_list.first_reference ();
608 if (ref)
610 target = chkp_maybe_create_clone (ref->referred->decl);
611 clone->create_reference (target, IPA_REF_ALIAS);
614 if (node->alias_target)
616 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
618 target = chkp_maybe_create_clone (node->alias_target);
619 clone->alias_target = target->decl;
621 else
622 clone->alias_target = node->alias_target;
626 /* Add IPA reference. It's main role is to keep instrumented
627 version reachable while original node is reachable. */
628 ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
631 return clone;
634 /* Create clone for all functions to be instrumented. */
636 static unsigned int
637 chkp_versioning (void)
639 struct cgraph_node *node;
640 const char *reason;
642 bitmap_obstack_initialize (NULL);
644 FOR_EACH_DEFINED_FUNCTION (node)
646 if (!node->instrumentation_clone
647 && !node->instrumented_version
648 && !node->alias
649 && !node->thunk.thunk_p
650 && (!DECL_BUILT_IN (node->decl)
651 || (DECL_BUILT_IN_CLASS (node->decl) == BUILT_IN_NORMAL
652 && DECL_FUNCTION_CODE (node->decl) < BEGIN_CHKP_BUILTINS)))
654 if (chkp_instrumentable_p (node->decl))
655 chkp_maybe_create_clone (node->decl);
656 else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl),
657 node->decl)))
659 if (warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wchkp,
660 "function cannot be instrumented"))
661 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
666 /* Mark all aliases and thunks of functions with no instrumented
667 version as legacy function. */
668 FOR_EACH_DEFINED_FUNCTION (node)
670 if (!node->instrumentation_clone
671 && !node->instrumented_version
672 && (node->alias || node->thunk.thunk_p)
673 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
674 DECL_ATTRIBUTES (node->decl)
675 = tree_cons (get_identifier ("bnd_legacy"), NULL,
676 DECL_ATTRIBUTES (node->decl));
679 bitmap_obstack_release (NULL);
681 return 0;
684 /* In this pass we remove bodies of functions having
685 instrumented version. Functions with removed bodies
686 become a special kind of thunks to provide a connection
687 between calls to the original version and instrumented
688 function. */
690 static unsigned int
691 chkp_produce_thunks (bool early)
693 struct cgraph_node *node;
695 FOR_EACH_DEFINED_FUNCTION (node)
697 if (!node->instrumentation_clone
698 && node->instrumented_version
699 && gimple_has_body_p (node->decl)
700 && gimple_has_body_p (node->instrumented_version->decl)
701 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
702 || !early))
704 node->release_body ();
705 node->remove_callees ();
706 node->remove_all_references ();
708 node->thunk.thunk_p = true;
709 node->thunk.add_pointer_bounds_args = true;
710 node->create_edge (node->instrumented_version, NULL,
711 0, CGRAPH_FREQ_BASE);
712 node->create_reference (node->instrumented_version,
713 IPA_REF_CHKP, NULL);
714 /* Thunk shouldn't be a cdtor. */
715 DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
716 DECL_STATIC_DESTRUCTOR (node->decl) = 0;
720 /* Mark instrumentation clones created for aliases and thunks
721 as insttrumented so they could be removed as unreachable
722 now. */
723 if (!early)
725 FOR_EACH_DEFINED_FUNCTION (node)
727 if (node->instrumentation_clone
728 && (node->alias || node->thunk.thunk_p)
729 && !chkp_function_instrumented_p (node->decl))
730 chkp_function_mark_instrumented (node->decl);
734 return TODO_remove_functions;
737 const pass_data pass_data_ipa_chkp_versioning =
739 SIMPLE_IPA_PASS, /* type */
740 "chkp_versioning", /* name */
741 OPTGROUP_NONE, /* optinfo_flags */
742 TV_NONE, /* tv_id */
743 0, /* properties_required */
744 0, /* properties_provided */
745 0, /* properties_destroyed */
746 0, /* todo_flags_start */
747 0 /* todo_flags_finish */
750 const pass_data pass_data_ipa_chkp_early_produce_thunks =
752 SIMPLE_IPA_PASS, /* type */
753 "chkp_ecleanup", /* name */
754 OPTGROUP_NONE, /* optinfo_flags */
755 TV_NONE, /* tv_id */
756 0, /* properties_required */
757 0, /* properties_provided */
758 0, /* properties_destroyed */
759 0, /* todo_flags_start */
760 0 /* todo_flags_finish */
763 const pass_data pass_data_ipa_chkp_produce_thunks =
765 SIMPLE_IPA_PASS, /* type */
766 "chkp_cleanup", /* name */
767 OPTGROUP_NONE, /* optinfo_flags */
768 TV_NONE, /* tv_id */
769 0, /* properties_required */
770 0, /* properties_provided */
771 0, /* properties_destroyed */
772 0, /* todo_flags_start */
773 0 /* todo_flags_finish */
776 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
778 public:
779 pass_ipa_chkp_versioning (gcc::context *ctxt)
780 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
783 /* opt_pass methods: */
784 virtual opt_pass * clone ()
786 return new pass_ipa_chkp_versioning (m_ctxt);
789 virtual bool gate (function *)
791 return flag_check_pointer_bounds;
794 virtual unsigned int execute (function *)
796 return chkp_versioning ();
799 }; // class pass_ipa_chkp_versioning
801 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
803 public:
804 pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
805 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
808 /* opt_pass methods: */
809 virtual opt_pass * clone ()
811 return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
814 virtual bool gate (function *)
816 return flag_check_pointer_bounds;
819 virtual unsigned int execute (function *)
821 return chkp_produce_thunks (true);
824 }; // class pass_chkp_produce_thunks
826 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
828 public:
829 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
830 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
833 /* opt_pass methods: */
834 virtual opt_pass * clone ()
836 return new pass_ipa_chkp_produce_thunks (m_ctxt);
839 virtual bool gate (function *)
841 return flag_check_pointer_bounds;
844 virtual unsigned int execute (function *)
846 return chkp_produce_thunks (false);
849 }; // class pass_chkp_produce_thunks
851 simple_ipa_opt_pass *
852 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
854 return new pass_ipa_chkp_versioning (ctxt);
857 simple_ipa_opt_pass *
858 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
860 return new pass_ipa_chkp_early_produce_thunks (ctxt);
863 simple_ipa_opt_pass *
864 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
866 return new pass_ipa_chkp_produce_thunks (ctxt);