* config/i386/i386.h (TARGET_SUPPORTS_WIDE_INT): New define.
[official-gcc.git] / gcc / ipa-chkp.c
blob23e08cbfc6f55a13657af0c84f23b7a4d2060441
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 "hash-set.h"
25 #include "machmode.h"
26 #include "vec.h"
27 #include "double-int.h"
28 #include "input.h"
29 #include "alias.h"
30 #include "symtab.h"
31 #include "options.h"
32 #include "wide-int.h"
33 #include "inchash.h"
34 #include "tree.h"
35 #include "fold-const.h"
36 #include "stor-layout.h"
37 #include "tree-pass.h"
38 #include "stringpool.h"
39 #include "bitmap.h"
40 #include "gimple-expr.h"
41 #include "tm.h"
42 #include "hard-reg-set.h"
43 #include "function.h"
44 #include "is-a.h"
45 #include "tree-ssa-alias.h"
46 #include "predict.h"
47 #include "basic-block.h"
48 #include "gimple.h"
49 #include "ipa-ref.h"
50 #include "lto-streamer.h"
51 #include "cgraph.h"
52 #include "tree-chkp.h"
53 #include "tree-inline.h"
54 #include "ipa-chkp.h"
56 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
58 In instrumented code each pointer is provided with bounds. For input
59 pointer parameters it means we also have bounds passed. For calls it
60 means we have additional bounds arguments for pointer arguments.
62 To have all IPA optimizations working correctly we have to express
63 dataflow between passed and received bounds explicitly via additional
64 entries in function declaration arguments list and in function type.
65 Since we may have both instrumented and not instrumented code at the
66 same time, we cannot replace all original functions with their
67 instrumented variants. Therefore we create clones (versions) instead.
69 Instrumentation clones creation is a separate IPA pass which is a part
70 of early local passes. Clones are created after SSA is built (because
71 instrumentation pass works on SSA) and before any transformations
72 which may change pointer flow and therefore lead to incorrect code
73 instrumentation (possibly causing false bounds check failures).
75 Instrumentation clones have pointer bounds arguments added right after
76 pointer arguments. Clones have assembler name of the original
77 function with suffix added. New assembler name is in transparent
78 alias chain with the original name. Thus we expect all calls to the
79 original and instrumented functions look similar in assembler.
81 During instrumentation versioning pass we create instrumented versions
82 of all function with body and also for all their aliases and thunks.
83 Clones for functions with no body are created on demand (usually
84 during call instrumentation).
86 Original and instrumented function nodes are connected with IPA
87 reference IPA_REF_CHKP. It is mostly done to have reachability
88 analysis working correctly. We may have no references to the
89 instrumented function in the code but it still should be counted
90 as reachable if the original function is reachable.
92 When original function bodies are not needed anymore we release
93 them and transform functions into a special kind of thunks. Each
94 thunk has a call edge to the instrumented version. These thunks
95 help to keep externally visible instrumented functions visible
96 when linker resolution files are used. Linker has no info about
97 connection between original and instrumented function and
98 therefore we may wrongly decide (due to difference in assembler
99 names) that instrumented function version is local and can be
100 removed. */
102 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
103 #define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
105 /* Return 1 calls to FNDECL should be replaced with
106 a call to wrapper function. */
107 static bool
108 chkp_wrap_function (tree fndecl)
110 if (!flag_chkp_use_wrappers)
111 return false;
113 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
115 switch (DECL_FUNCTION_CODE (fndecl))
117 case BUILT_IN_STRLEN:
118 case BUILT_IN_STRCPY:
119 case BUILT_IN_STRNCPY:
120 case BUILT_IN_STPCPY:
121 case BUILT_IN_STPNCPY:
122 case BUILT_IN_STRCAT:
123 case BUILT_IN_STRNCAT:
124 case BUILT_IN_MEMCPY:
125 case BUILT_IN_MEMPCPY:
126 case BUILT_IN_MEMSET:
127 case BUILT_IN_MEMMOVE:
128 case BUILT_IN_BZERO:
129 case BUILT_IN_MALLOC:
130 case BUILT_IN_CALLOC:
131 case BUILT_IN_REALLOC:
132 return 1;
134 default:
135 return 0;
139 return false;
142 /* Build a clone of FNDECL with a modified name. */
144 static tree
145 chkp_build_instrumented_fndecl (tree fndecl)
147 tree new_decl = copy_node (fndecl);
148 tree new_name;
149 std::string s;
151 /* called_as_built_in checks DECL_NAME to identify calls to
152 builtins. We want instrumented calls to builtins to be
153 recognized by called_as_built_in. Therefore use original
154 DECL_NAME for cloning with no prefixes. */
155 s = IDENTIFIER_POINTER (DECL_NAME (fndecl));
156 s += ".chkp";
157 DECL_NAME (new_decl) = get_identifier (s.c_str ());
159 /* References to the original and to the instrumented version
160 should look the same in the output assembly. And we cannot
161 use the same assembler name for the instrumented version
162 because it conflicts with decl merging algorithms in LTO.
163 Achieve the result by using transparent alias name for the
164 instrumented version. */
165 if (chkp_wrap_function(fndecl))
167 s = CHKP_WRAPPER_SYMBOL_PREFIX;
168 s += IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
169 new_name = get_identifier (s.c_str ());
171 else
173 s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
174 s += ".chkp";
175 new_name = get_identifier (s.c_str ());
176 IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
177 TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
179 SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
181 /* For functions with body versioning will make a copy of arguments.
182 For functions with no body we need to do it here. */
183 if (!gimple_has_body_p (fndecl))
184 DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
186 /* We are going to modify attributes list and therefore should
187 make own copy. */
188 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
190 /* Change builtin function code. */
191 if (DECL_BUILT_IN (new_decl))
193 gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL);
194 gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS);
195 DECL_FUNCTION_CODE (new_decl)
196 = (enum built_in_function)(DECL_FUNCTION_CODE (new_decl)
197 + BEGIN_CHKP_BUILTINS + 1);
200 return new_decl;
204 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
205 Integer operands are replaced with values according to
206 INDEXES map having LEN elements. For operands out of len
207 we just add DELTA. */
209 static void
210 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
211 unsigned *indexes, int len, int delta)
213 tree attr = lookup_attribute (attr_name, attrs);
214 tree op;
216 if (!attr)
217 return;
219 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
220 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
222 int idx;
224 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
225 continue;
227 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
229 /* If idx exceeds indexes length then we just
230 keep it at the same distance from the last
231 known arg. */
232 if (idx > len)
233 idx += delta;
234 else
235 idx = indexes[idx - 1] + 1;
236 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
240 /* Make a copy of function type ORIG_TYPE adding pointer
241 bounds as additional arguments. */
243 tree
244 chkp_copy_function_type_adding_bounds (tree orig_type)
246 tree type;
247 tree arg_type, attrs;
248 unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
249 unsigned *indexes = XALLOCAVEC (unsigned, len);
250 unsigned idx = 0, new_idx = 0;
252 for (arg_type = TYPE_ARG_TYPES (orig_type);
253 arg_type;
254 arg_type = TREE_CHAIN (arg_type))
255 if (TREE_VALUE (arg_type) == void_type_node)
256 continue;
257 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
258 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
259 TREE_VALUE (arg_type), true)
260 || chkp_type_has_pointer (TREE_VALUE (arg_type)))
261 break;
263 /* We may use original type if there are no bounds passed. */
264 if (!arg_type)
265 return orig_type;
267 type = copy_node (orig_type);
268 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
270 for (arg_type = TYPE_ARG_TYPES (type);
271 arg_type;
272 arg_type = TREE_CHAIN (arg_type))
274 indexes[idx++] = new_idx++;
276 /* pass_by_reference returns 1 for void type,
277 so check for it first. */
278 if (TREE_VALUE (arg_type) == void_type_node)
279 continue;
280 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
281 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
282 TREE_VALUE (arg_type), true))
284 tree new_type = build_tree_list (NULL_TREE,
285 pointer_bounds_type_node);
286 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
287 TREE_CHAIN (arg_type) = new_type;
289 arg_type = TREE_CHAIN (arg_type);
290 new_idx++;
292 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
294 bitmap slots = BITMAP_ALLOC (NULL);
295 bitmap_iterator bi;
296 unsigned bnd_no;
298 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
300 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
302 tree new_type = build_tree_list (NULL_TREE,
303 pointer_bounds_type_node);
304 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
305 TREE_CHAIN (arg_type) = new_type;
307 arg_type = TREE_CHAIN (arg_type);
308 new_idx++;
310 BITMAP_FREE (slots);
314 /* If function type has attribute with arg indexes then
315 we have to copy it fixing attribute ops. Map for
316 fixing is in indexes array. */
317 attrs = TYPE_ATTRIBUTES (type);
318 if (lookup_attribute ("nonnull", attrs)
319 || lookup_attribute ("format", attrs)
320 || lookup_attribute ("format_arg", attrs))
322 int delta = new_idx - len;
323 attrs = copy_list (TYPE_ATTRIBUTES (type));
324 chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
325 chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
326 chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
327 TYPE_ATTRIBUTES (type) = attrs;
330 return type;
333 /* For given function FNDECL add bounds arguments to arguments
334 list. */
336 static void
337 chkp_add_bounds_params_to_function (tree fndecl)
339 tree arg;
341 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
342 if (BOUNDED_P (arg))
344 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
345 tree new_arg;
347 if (DECL_NAME (arg))
348 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
349 else
351 char uid[25];
352 snprintf (uid, 25, "D.%u", DECL_UID (arg));
353 new_name += uid;
356 new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
357 get_identifier (new_name.c_str ()),
358 pointer_bounds_type_node);
359 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
360 DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
361 DECL_ARTIFICIAL (new_arg) = 1;
362 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
363 DECL_CHAIN (arg) = new_arg;
365 arg = DECL_CHAIN (arg);
368 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
370 tree orig_arg = arg;
371 bitmap slots = BITMAP_ALLOC (NULL);
372 bitmap_iterator bi;
373 unsigned bnd_no;
375 chkp_find_bound_slots (TREE_TYPE (arg), slots);
377 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
379 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
380 tree new_arg;
381 char offs[25];
383 if (DECL_NAME (orig_arg))
384 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
385 else
387 snprintf (offs, 25, "D.%u", DECL_UID (arg));
388 new_name += offs;
390 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
392 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
393 PARM_DECL,
394 get_identifier (new_name.c_str ()),
395 pointer_bounds_type_node);
396 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
397 DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
398 DECL_ARTIFICIAL (new_arg) = 1;
399 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
400 DECL_CHAIN (arg) = new_arg;
402 arg = DECL_CHAIN (arg);
404 BITMAP_FREE (slots);
407 TREE_TYPE (fndecl) =
408 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
411 /* Return an instrumentation clone for builtin function
412 FNDECL. Create one if needed. */
414 tree
415 chkp_maybe_clone_builtin_fndecl (tree fndecl)
417 tree clone;
418 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
420 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
421 && fcode < BEGIN_CHKP_BUILTINS);
423 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
424 clone = builtin_decl_explicit (fcode);
425 if (clone)
426 return clone;
428 clone = chkp_build_instrumented_fndecl (fndecl);
429 chkp_add_bounds_params_to_function (clone);
431 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
433 set_builtin_decl (fcode, clone, false);
435 return clone;
438 /* Return 1 if function FNDECL should be instrumented. */
440 bool
441 chkp_instrumentable_p (tree fndecl)
443 struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
444 return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
445 && (!flag_chkp_instrument_marked_only
446 || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl)))
447 && (!fn || !copy_forbidden (fn, fndecl)));
450 /* Return clone created for instrumentation of NODE or NULL. */
452 cgraph_node *
453 chkp_maybe_create_clone (tree fndecl)
455 cgraph_node *node = cgraph_node::get_create (fndecl);
456 cgraph_node *clone = node->instrumented_version;
458 gcc_assert (!node->instrumentation_clone);
460 if (DECL_BUILT_IN (fndecl)
461 && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
462 || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
463 return NULL;
465 clone = node->instrumented_version;
467 /* Some instrumented builtin function calls may be optimized and
468 cgraph nodes may be removed as unreachable. Later optimizations
469 may generate new calls to removed functions and in this case
470 we have to recreate cgraph node. FUNCTION_DECL for instrumented
471 builtin still exists and should be reused in such case. */
472 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
473 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))
474 && !clone)
476 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
477 tree new_decl;
479 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
480 new_decl = builtin_decl_explicit (fncode);
482 /* We've actually already created an instrumented clone once.
483 Restore it. */
484 if (new_decl)
486 clone = cgraph_node::get (new_decl);
488 if (!clone)
490 gcc_assert (!gimple_has_body_p (fndecl));
491 clone = cgraph_node::get_create (new_decl);
492 clone->externally_visible = node->externally_visible;
493 clone->local = node->local;
494 clone->address_taken = node->address_taken;
495 clone->thunk = node->thunk;
496 clone->alias = node->alias;
497 clone->weakref = node->weakref;
498 clone->cpp_implicit_alias = node->cpp_implicit_alias;
499 clone->orig_decl = fndecl;
500 clone->instrumentation_clone = true;
503 clone->instrumented_version = node;
504 node->instrumented_version = clone;
508 if (!clone)
510 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
511 struct cgraph_edge *e;
512 struct ipa_ref *ref;
513 int i;
515 clone = node->create_version_clone (new_decl, vNULL, NULL);
516 clone->externally_visible = node->externally_visible;
517 clone->local = node->local;
518 clone->address_taken = node->address_taken;
519 clone->thunk = node->thunk;
520 clone->alias = node->alias;
521 clone->weakref = node->weakref;
522 clone->cpp_implicit_alias = node->cpp_implicit_alias;
523 clone->instrumented_version = node;
524 clone->orig_decl = fndecl;
525 clone->instrumentation_clone = true;
526 node->instrumented_version = clone;
528 if (gimple_has_body_p (fndecl))
530 /* If function will not be instrumented, then it's instrumented
531 version is a thunk for the original. */
532 if (!chkp_instrumentable_p (fndecl))
534 clone->remove_callees ();
535 clone->remove_all_references ();
536 clone->thunk.thunk_p = true;
537 clone->thunk.add_pointer_bounds_args = true;
538 clone->create_edge (node, NULL, 0, CGRAPH_FREQ_BASE);
539 /* Thunk shouldn't be a cdtor. */
540 DECL_STATIC_CONSTRUCTOR (clone->decl) = 0;
541 DECL_STATIC_DESTRUCTOR (clone->decl) = 0;
543 else
545 tree_function_versioning (fndecl, new_decl, NULL, false,
546 NULL, false, NULL, NULL);
547 clone->lowered = true;
551 /* New params are inserted after versioning because it
552 actually copies args list from the original decl. */
553 chkp_add_bounds_params_to_function (new_decl);
555 /* Remember builtin fndecl. */
556 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
557 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
559 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
560 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
561 clone->decl, false);
564 /* Clones have the same comdat group as originals. */
565 if (node->same_comdat_group
566 || (DECL_ONE_ONLY (node->decl)
567 && !DECL_EXTERNAL (node->decl)))
568 clone->add_to_same_comdat_group (node);
570 if (gimple_has_body_p (fndecl))
571 symtab->call_cgraph_insertion_hooks (clone);
573 /* Clone all aliases. */
574 for (i = 0; node->iterate_direct_aliases (i, ref); i++)
576 struct cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
577 struct cgraph_node *chkp_alias
578 = chkp_maybe_create_clone (alias->decl);
579 chkp_alias->create_reference (clone, IPA_REF_ALIAS, NULL);
582 /* Clone all thunks. */
583 for (e = node->callers; e; e = e->next_caller)
584 if (e->caller->thunk.thunk_p
585 && !e->caller->thunk.add_pointer_bounds_args
586 && !e->caller->instrumentation_clone)
588 struct cgraph_node *thunk
589 = chkp_maybe_create_clone (e->caller->decl);
590 /* Redirect thunk clone edge to the node clone. */
591 thunk->callees->redirect_callee (clone);
594 /* For aliases and thunks we should make sure target is cloned
595 to have proper references and edges. */
596 if (node->thunk.thunk_p)
597 chkp_maybe_create_clone (node->callees->callee->decl);
598 else if (node->alias)
600 struct cgraph_node *target;
602 ref = node->ref_list.first_reference ();
603 if (ref)
604 chkp_maybe_create_clone (ref->referred->decl);
606 if (node->alias_target)
608 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
610 target = chkp_maybe_create_clone (node->alias_target);
611 clone->alias_target = target->decl;
613 else
614 clone->alias_target = node->alias_target;
618 /* Add IPA reference. It's main role is to keep instrumented
619 version reachable while original node is reachable. */
620 ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
623 return clone;
626 /* Create clone for all functions to be instrumented. */
628 static unsigned int
629 chkp_versioning (void)
631 struct cgraph_node *node;
632 const char *reason;
634 bitmap_obstack_initialize (NULL);
636 FOR_EACH_DEFINED_FUNCTION (node)
638 if (!node->instrumentation_clone
639 && !node->instrumented_version
640 && !node->alias
641 && !node->thunk.thunk_p
642 && (!DECL_BUILT_IN (node->decl)
643 || (DECL_BUILT_IN_CLASS (node->decl) == BUILT_IN_NORMAL
644 && DECL_FUNCTION_CODE (node->decl) < BEGIN_CHKP_BUILTINS)))
646 if (chkp_instrumentable_p (node->decl))
647 chkp_maybe_create_clone (node->decl);
648 else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl),
649 node->decl)))
651 if (warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wchkp,
652 "function cannot be instrumented"))
653 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
658 /* Mark all aliases and thunks of functions with no instrumented
659 version as legacy function. */
660 FOR_EACH_DEFINED_FUNCTION (node)
662 if (!node->instrumentation_clone
663 && !node->instrumented_version
664 && (node->alias || node->thunk.thunk_p)
665 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
666 DECL_ATTRIBUTES (node->decl)
667 = tree_cons (get_identifier ("bnd_legacy"), NULL,
668 DECL_ATTRIBUTES (node->decl));
671 bitmap_obstack_release (NULL);
673 return 0;
676 /* In this pass we remove bodies of functions having
677 instrumented version. Functions with removed bodies
678 become a special kind of thunks to provide a connection
679 between calls to the original version and instrumented
680 function. */
682 static unsigned int
683 chkp_produce_thunks (bool early)
685 struct cgraph_node *node;
687 FOR_EACH_DEFINED_FUNCTION (node)
689 if (!node->instrumentation_clone
690 && node->instrumented_version
691 && gimple_has_body_p (node->decl)
692 && gimple_has_body_p (node->instrumented_version->decl)
693 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
694 || !early))
696 node->release_body ();
697 node->remove_callees ();
698 node->remove_all_references ();
700 node->thunk.thunk_p = true;
701 node->thunk.add_pointer_bounds_args = true;
702 node->create_edge (node->instrumented_version, NULL,
703 0, CGRAPH_FREQ_BASE);
704 node->create_reference (node->instrumented_version,
705 IPA_REF_CHKP, NULL);
706 /* Thunk shouldn't be a cdtor. */
707 DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
708 DECL_STATIC_DESTRUCTOR (node->decl) = 0;
712 /* Mark instrumentation clones created for aliases and thunks
713 as insttrumented so they could be removed as unreachable
714 now. */
715 if (!early)
717 FOR_EACH_DEFINED_FUNCTION (node)
719 if (node->instrumentation_clone
720 && (node->alias || node->thunk.thunk_p)
721 && !chkp_function_instrumented_p (node->decl))
722 chkp_function_mark_instrumented (node->decl);
726 return TODO_remove_functions;
729 const pass_data pass_data_ipa_chkp_versioning =
731 SIMPLE_IPA_PASS, /* type */
732 "chkp_versioning", /* name */
733 OPTGROUP_NONE, /* optinfo_flags */
734 TV_NONE, /* tv_id */
735 0, /* properties_required */
736 0, /* properties_provided */
737 0, /* properties_destroyed */
738 0, /* todo_flags_start */
739 0 /* todo_flags_finish */
742 const pass_data pass_data_ipa_chkp_early_produce_thunks =
744 SIMPLE_IPA_PASS, /* type */
745 "chkp_ecleanup", /* name */
746 OPTGROUP_NONE, /* optinfo_flags */
747 TV_NONE, /* tv_id */
748 0, /* properties_required */
749 0, /* properties_provided */
750 0, /* properties_destroyed */
751 0, /* todo_flags_start */
752 0 /* todo_flags_finish */
755 const pass_data pass_data_ipa_chkp_produce_thunks =
757 SIMPLE_IPA_PASS, /* type */
758 "chkp_cleanup", /* name */
759 OPTGROUP_NONE, /* optinfo_flags */
760 TV_NONE, /* tv_id */
761 0, /* properties_required */
762 0, /* properties_provided */
763 0, /* properties_destroyed */
764 0, /* todo_flags_start */
765 0 /* todo_flags_finish */
768 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
770 public:
771 pass_ipa_chkp_versioning (gcc::context *ctxt)
772 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
775 /* opt_pass methods: */
776 virtual opt_pass * clone ()
778 return new pass_ipa_chkp_versioning (m_ctxt);
781 virtual bool gate (function *)
783 return flag_check_pointer_bounds;
786 virtual unsigned int execute (function *)
788 return chkp_versioning ();
791 }; // class pass_ipa_chkp_versioning
793 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
795 public:
796 pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
797 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
800 /* opt_pass methods: */
801 virtual opt_pass * clone ()
803 return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
806 virtual bool gate (function *)
808 return flag_check_pointer_bounds;
811 virtual unsigned int execute (function *)
813 return chkp_produce_thunks (true);
816 }; // class pass_chkp_produce_thunks
818 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
820 public:
821 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
822 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
825 /* opt_pass methods: */
826 virtual opt_pass * clone ()
828 return new pass_ipa_chkp_produce_thunks (m_ctxt);
831 virtual bool gate (function *)
833 return flag_check_pointer_bounds;
836 virtual unsigned int execute (function *)
838 return chkp_produce_thunks (false);
841 }; // class pass_chkp_produce_thunks
843 simple_ipa_opt_pass *
844 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
846 return new pass_ipa_chkp_versioning (ctxt);
849 simple_ipa_opt_pass *
850 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
852 return new pass_ipa_chkp_early_produce_thunks (ctxt);
855 simple_ipa_opt_pass *
856 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
858 return new pass_ipa_chkp_produce_thunks (ctxt);