2015-06-25 Zhouyi Zhou <yizhouzhou@ict.ac.cn>
[official-gcc.git] / gcc / ipa-chkp.c
blob96f269cd0a936b7b4b10df2db270c90bb001639b
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 "alias.h"
25 #include "symtab.h"
26 #include "options.h"
27 #include "tree.h"
28 #include "fold-const.h"
29 #include "stor-layout.h"
30 #include "tree-pass.h"
31 #include "stringpool.h"
32 #include "bitmap.h"
33 #include "gimple-expr.h"
34 #include "tm.h"
35 #include "hard-reg-set.h"
36 #include "function.h"
37 #include "tree-ssa-alias.h"
38 #include "predict.h"
39 #include "basic-block.h"
40 #include "gimple.h"
41 #include "ipa-ref.h"
42 #include "lto-streamer.h"
43 #include "cgraph.h"
44 #include "tree-chkp.h"
45 #include "tree-inline.h"
46 #include "ipa-chkp.h"
48 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
50 In instrumented code each pointer is provided with bounds. For input
51 pointer parameters it means we also have bounds passed. For calls it
52 means we have additional bounds arguments for pointer arguments.
54 To have all IPA optimizations working correctly we have to express
55 dataflow between passed and received bounds explicitly via additional
56 entries in function declaration arguments list and in function type.
57 Since we may have both instrumented and not instrumented code at the
58 same time, we cannot replace all original functions with their
59 instrumented variants. Therefore we create clones (versions) instead.
61 Instrumentation clones creation is a separate IPA pass which is a part
62 of early local passes. Clones are created after SSA is built (because
63 instrumentation pass works on SSA) and before any transformations
64 which may change pointer flow and therefore lead to incorrect code
65 instrumentation (possibly causing false bounds check failures).
67 Instrumentation clones have pointer bounds arguments added right after
68 pointer arguments. Clones have assembler name of the original
69 function with suffix added. New assembler name is in transparent
70 alias chain with the original name. Thus we expect all calls to the
71 original and instrumented functions look similar in assembler.
73 During instrumentation versioning pass we create instrumented versions
74 of all function with body and also for all their aliases and thunks.
75 Clones for functions with no body are created on demand (usually
76 during call instrumentation).
78 Original and instrumented function nodes are connected with IPA
79 reference IPA_REF_CHKP. It is mostly done to have reachability
80 analysis working correctly. We may have no references to the
81 instrumented function in the code but it still should be counted
82 as reachable if the original function is reachable.
84 When original function bodies are not needed anymore we release
85 them and transform functions into a special kind of thunks. Each
86 thunk has a call edge to the instrumented version. These thunks
87 help to keep externally visible instrumented functions visible
88 when linker resolution files are used. Linker has no info about
89 connection between original and instrumented function and
90 therefore we may wrongly decide (due to difference in assembler
91 names) that instrumented function version is local and can be
92 removed. */
94 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
95 #define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
97 /* Return 1 calls to FNDECL should be replaced with
98 a call to wrapper function. */
99 bool
100 chkp_wrap_function (tree fndecl)
102 if (!flag_chkp_use_wrappers)
103 return false;
105 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
107 switch (DECL_FUNCTION_CODE (fndecl))
109 case BUILT_IN_STRLEN:
110 case BUILT_IN_STRCPY:
111 case BUILT_IN_STRNCPY:
112 case BUILT_IN_STPCPY:
113 case BUILT_IN_STPNCPY:
114 case BUILT_IN_STRCAT:
115 case BUILT_IN_STRNCAT:
116 case BUILT_IN_MEMCPY:
117 case BUILT_IN_MEMPCPY:
118 case BUILT_IN_MEMSET:
119 case BUILT_IN_MEMMOVE:
120 case BUILT_IN_BZERO:
121 case BUILT_IN_MALLOC:
122 case BUILT_IN_CALLOC:
123 case BUILT_IN_REALLOC:
124 return 1;
126 default:
127 return 0;
131 return false;
134 static const char *
135 chkp_wrap_function_name (tree fndecl)
137 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL);
139 switch (DECL_FUNCTION_CODE (fndecl))
141 case BUILT_IN_STRLEN:
142 return CHKP_WRAPPER_SYMBOL_PREFIX "strlen";
143 case BUILT_IN_STRCPY:
144 return CHKP_WRAPPER_SYMBOL_PREFIX "strcpy";
145 case BUILT_IN_STRNCPY:
146 return CHKP_WRAPPER_SYMBOL_PREFIX "strncpy";
147 case BUILT_IN_STPCPY:
148 return CHKP_WRAPPER_SYMBOL_PREFIX "stpcpy";
149 case BUILT_IN_STPNCPY:
150 return CHKP_WRAPPER_SYMBOL_PREFIX "stpncpy";
151 case BUILT_IN_STRCAT:
152 return CHKP_WRAPPER_SYMBOL_PREFIX "strcat";
153 case BUILT_IN_STRNCAT:
154 return CHKP_WRAPPER_SYMBOL_PREFIX "strncat";
155 case BUILT_IN_MEMCPY:
156 return CHKP_WRAPPER_SYMBOL_PREFIX "memcpy";
157 case BUILT_IN_MEMPCPY:
158 return CHKP_WRAPPER_SYMBOL_PREFIX "mempcpy";
159 case BUILT_IN_MEMSET:
160 return CHKP_WRAPPER_SYMBOL_PREFIX "memset";
161 case BUILT_IN_MEMMOVE:
162 return CHKP_WRAPPER_SYMBOL_PREFIX "memmove";
163 case BUILT_IN_BZERO:
164 return CHKP_WRAPPER_SYMBOL_PREFIX "bzero";
165 case BUILT_IN_MALLOC:
166 return CHKP_WRAPPER_SYMBOL_PREFIX "malloc";
167 case BUILT_IN_CALLOC:
168 return CHKP_WRAPPER_SYMBOL_PREFIX "calloc";
169 case BUILT_IN_REALLOC:
170 return CHKP_WRAPPER_SYMBOL_PREFIX "realloc";
172 default:
173 gcc_unreachable ();
176 return "";
179 /* Build a clone of FNDECL with a modified name. */
181 static tree
182 chkp_build_instrumented_fndecl (tree fndecl)
184 tree new_decl = copy_node (fndecl);
185 tree new_name;
186 std::string s;
188 /* called_as_built_in checks DECL_NAME to identify calls to
189 builtins. We want instrumented calls to builtins to be
190 recognized by called_as_built_in. Therefore use original
191 DECL_NAME for cloning with no prefixes. */
192 s = IDENTIFIER_POINTER (DECL_NAME (fndecl));
193 s += ".chkp";
194 DECL_NAME (new_decl) = get_identifier (s.c_str ());
196 /* References to the original and to the instrumented version
197 should look the same in the output assembly. And we cannot
198 use the same assembler name for the instrumented version
199 because it conflicts with decl merging algorithms in LTO.
200 Achieve the result by using transparent alias name for the
201 instrumented version. */
202 if (chkp_wrap_function(fndecl))
204 new_name = get_identifier (chkp_wrap_function_name (fndecl));
205 DECL_VISIBILITY (new_decl) = VISIBILITY_DEFAULT;
207 else
209 s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
210 s += ".chkp";
211 new_name = get_identifier (s.c_str ());
212 IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
213 TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
215 SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
217 /* For functions with body versioning will make a copy of arguments.
218 For functions with no body we need to do it here. */
219 if (!gimple_has_body_p (fndecl))
220 DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
222 /* We are going to modify attributes list and therefore should
223 make own copy. */
224 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
226 /* Change builtin function code. */
227 if (DECL_BUILT_IN (new_decl))
229 gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL);
230 gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS);
231 DECL_FUNCTION_CODE (new_decl)
232 = (enum built_in_function)(DECL_FUNCTION_CODE (new_decl)
233 + BEGIN_CHKP_BUILTINS + 1);
236 return new_decl;
240 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
241 Integer operands are replaced with values according to
242 INDEXES map having LEN elements. For operands out of len
243 we just add DELTA. */
245 static void
246 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
247 unsigned *indexes, int len, int delta)
249 tree attr = lookup_attribute (attr_name, attrs);
250 tree op;
252 if (!attr)
253 return;
255 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
256 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
258 int idx;
260 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
261 continue;
263 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
265 /* If idx exceeds indexes length then we just
266 keep it at the same distance from the last
267 known arg. */
268 if (idx > len)
269 idx += delta;
270 else
271 idx = indexes[idx - 1] + 1;
272 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
276 /* Make a copy of function type ORIG_TYPE adding pointer
277 bounds as additional arguments. */
279 tree
280 chkp_copy_function_type_adding_bounds (tree orig_type)
282 tree type;
283 tree arg_type, attrs;
284 unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
285 unsigned *indexes = XALLOCAVEC (unsigned, len);
286 unsigned idx = 0, new_idx = 0;
288 for (arg_type = TYPE_ARG_TYPES (orig_type);
289 arg_type;
290 arg_type = TREE_CHAIN (arg_type))
291 if (TREE_VALUE (arg_type) == void_type_node)
292 continue;
293 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
294 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
295 TREE_VALUE (arg_type), true)
296 || chkp_type_has_pointer (TREE_VALUE (arg_type)))
297 break;
299 /* We may use original type if there are no bounds passed. */
300 if (!arg_type)
301 return orig_type;
303 type = build_distinct_type_copy (orig_type);
304 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
306 for (arg_type = TYPE_ARG_TYPES (type);
307 arg_type;
308 arg_type = TREE_CHAIN (arg_type))
310 indexes[idx++] = new_idx++;
312 /* pass_by_reference returns 1 for void type,
313 so check for it first. */
314 if (TREE_VALUE (arg_type) == void_type_node)
315 continue;
316 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
317 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
318 TREE_VALUE (arg_type), true))
320 tree new_type = build_tree_list (NULL_TREE,
321 pointer_bounds_type_node);
322 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
323 TREE_CHAIN (arg_type) = new_type;
325 arg_type = TREE_CHAIN (arg_type);
326 new_idx++;
328 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
330 bitmap slots = BITMAP_ALLOC (NULL);
331 bitmap_iterator bi;
332 unsigned bnd_no;
334 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
336 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
338 tree new_type = build_tree_list (NULL_TREE,
339 pointer_bounds_type_node);
340 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
341 TREE_CHAIN (arg_type) = new_type;
343 arg_type = TREE_CHAIN (arg_type);
344 new_idx++;
346 BITMAP_FREE (slots);
350 /* If function type has attribute with arg indexes then
351 we have to copy it fixing attribute ops. Map for
352 fixing is in indexes array. */
353 attrs = TYPE_ATTRIBUTES (type);
354 if (lookup_attribute ("nonnull", attrs)
355 || lookup_attribute ("format", attrs)
356 || lookup_attribute ("format_arg", attrs))
358 int delta = new_idx - len;
359 attrs = copy_list (TYPE_ATTRIBUTES (type));
360 chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
361 chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
362 chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
363 TYPE_ATTRIBUTES (type) = attrs;
366 return type;
369 /* For given function FNDECL add bounds arguments to arguments
370 list. */
372 static void
373 chkp_add_bounds_params_to_function (tree fndecl)
375 tree arg;
377 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
378 if (BOUNDED_P (arg))
380 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
381 tree new_arg;
383 if (DECL_NAME (arg))
384 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
385 else
387 char uid[25];
388 snprintf (uid, 25, "D.%u", DECL_UID (arg));
389 new_name += uid;
392 new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
393 get_identifier (new_name.c_str ()),
394 pointer_bounds_type_node);
395 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
396 DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
397 DECL_ARTIFICIAL (new_arg) = 1;
398 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
399 DECL_CHAIN (arg) = new_arg;
401 arg = DECL_CHAIN (arg);
404 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
406 tree orig_arg = arg;
407 bitmap slots = BITMAP_ALLOC (NULL);
408 bitmap_iterator bi;
409 unsigned bnd_no;
411 chkp_find_bound_slots (TREE_TYPE (arg), slots);
413 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
415 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
416 tree new_arg;
417 char offs[25];
419 if (DECL_NAME (orig_arg))
420 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
421 else
423 snprintf (offs, 25, "D.%u", DECL_UID (arg));
424 new_name += offs;
426 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
428 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
429 PARM_DECL,
430 get_identifier (new_name.c_str ()),
431 pointer_bounds_type_node);
432 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
433 DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
434 DECL_ARTIFICIAL (new_arg) = 1;
435 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
436 DECL_CHAIN (arg) = new_arg;
438 arg = DECL_CHAIN (arg);
440 BITMAP_FREE (slots);
443 TREE_TYPE (fndecl) =
444 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
447 /* Return an instrumentation clone for builtin function
448 FNDECL. Create one if needed. */
450 tree
451 chkp_maybe_clone_builtin_fndecl (tree fndecl)
453 tree clone;
454 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
456 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
457 && fcode < BEGIN_CHKP_BUILTINS);
459 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
460 clone = builtin_decl_explicit (fcode);
461 if (clone)
462 return clone;
464 clone = chkp_build_instrumented_fndecl (fndecl);
465 chkp_add_bounds_params_to_function (clone);
467 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
469 set_builtin_decl (fcode, clone, false);
471 return clone;
474 /* Return 1 if function FNDECL should be instrumented. */
476 bool
477 chkp_instrumentable_p (tree fndecl)
479 struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
480 return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
481 && (!flag_chkp_instrument_marked_only
482 || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl)))
483 && (!fn || !copy_forbidden (fn, fndecl)));
486 /* Return clone created for instrumentation of NODE or NULL. */
488 cgraph_node *
489 chkp_maybe_create_clone (tree fndecl)
491 cgraph_node *node = cgraph_node::get_create (fndecl);
492 cgraph_node *clone = node->instrumented_version;
494 gcc_assert (!node->instrumentation_clone);
496 if (DECL_BUILT_IN (fndecl)
497 && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
498 || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
499 return NULL;
501 clone = node->instrumented_version;
503 /* Some instrumented builtin function calls may be optimized and
504 cgraph nodes may be removed as unreachable. Later optimizations
505 may generate new calls to removed functions and in this case
506 we have to recreate cgraph node. FUNCTION_DECL for instrumented
507 builtin still exists and should be reused in such case. */
508 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
509 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))
510 && !clone)
512 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
513 tree new_decl;
515 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
516 new_decl = builtin_decl_explicit (fncode);
518 /* We've actually already created an instrumented clone once.
519 Restore it. */
520 if (new_decl)
522 clone = cgraph_node::get (new_decl);
524 if (!clone)
526 gcc_assert (!gimple_has_body_p (fndecl));
527 clone = cgraph_node::get_create (new_decl);
528 clone->externally_visible = node->externally_visible;
529 clone->local = node->local;
530 clone->address_taken = node->address_taken;
531 clone->thunk = node->thunk;
532 clone->alias = node->alias;
533 clone->weakref = node->weakref;
534 clone->cpp_implicit_alias = node->cpp_implicit_alias;
535 clone->orig_decl = fndecl;
536 clone->instrumentation_clone = true;
539 clone->instrumented_version = node;
540 node->instrumented_version = clone;
544 if (!clone)
546 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
547 struct cgraph_edge *e;
548 struct ipa_ref *ref;
549 int i;
551 clone = node->create_version_clone (new_decl, vNULL, NULL);
552 clone->externally_visible = node->externally_visible;
553 clone->local = node->local;
554 clone->address_taken = node->address_taken;
555 clone->thunk = node->thunk;
556 clone->alias = node->alias;
557 clone->weakref = node->weakref;
558 clone->cpp_implicit_alias = node->cpp_implicit_alias;
559 clone->instrumented_version = node;
560 clone->orig_decl = fndecl;
561 clone->instrumentation_clone = true;
562 node->instrumented_version = clone;
564 if (gimple_has_body_p (fndecl))
566 gcc_assert (chkp_instrumentable_p (fndecl));
567 tree_function_versioning (fndecl, new_decl, NULL, false,
568 NULL, false, NULL, NULL);
569 clone->lowered = true;
572 /* New params are inserted after versioning because it
573 actually copies args list from the original decl. */
574 chkp_add_bounds_params_to_function (new_decl);
576 /* Remember builtin fndecl. */
577 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
578 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
580 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
581 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
582 clone->decl, false);
585 /* Clones have the same comdat group as originals. */
586 if (node->same_comdat_group
587 || (DECL_ONE_ONLY (node->decl)
588 && !DECL_EXTERNAL (node->decl)))
589 clone->add_to_same_comdat_group (node);
591 if (gimple_has_body_p (fndecl))
592 symtab->call_cgraph_insertion_hooks (clone);
594 /* Clone all aliases. */
595 for (i = 0; node->iterate_direct_aliases (i, ref); i++)
596 chkp_maybe_create_clone (ref->referring->decl);
598 /* Clone all thunks. */
599 for (e = node->callers; e; e = e->next_caller)
600 if (e->caller->thunk.thunk_p
601 && !e->caller->thunk.add_pointer_bounds_args
602 && !e->caller->instrumentation_clone)
604 struct cgraph_node *thunk
605 = chkp_maybe_create_clone (e->caller->decl);
606 /* Redirect thunk clone edge to the node clone. */
607 thunk->callees->redirect_callee (clone);
610 /* For aliases and thunks we should make sure target is cloned
611 to have proper references and edges. */
612 if (node->thunk.thunk_p)
613 chkp_maybe_create_clone (node->callees->callee->decl);
614 else if (node->alias)
616 struct cgraph_node *target;
618 ref = node->ref_list.first_reference ();
619 if (ref)
621 target = chkp_maybe_create_clone (ref->referred->decl);
622 clone->create_reference (target, IPA_REF_ALIAS);
625 if (node->alias_target)
627 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
629 target = chkp_maybe_create_clone (node->alias_target);
630 clone->alias_target = target->decl;
632 else
633 clone->alias_target = node->alias_target;
637 /* Add IPA reference. It's main role is to keep instrumented
638 version reachable while original node is reachable. */
639 ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
642 return clone;
645 /* Create clone for all functions to be instrumented. */
647 static unsigned int
648 chkp_versioning (void)
650 struct cgraph_node *node;
651 const char *reason;
653 bitmap_obstack_initialize (NULL);
655 FOR_EACH_DEFINED_FUNCTION (node)
657 if (!node->instrumentation_clone
658 && !node->instrumented_version
659 && !node->alias
660 && !node->thunk.thunk_p
661 && (!DECL_BUILT_IN (node->decl)
662 || (DECL_BUILT_IN_CLASS (node->decl) == BUILT_IN_NORMAL
663 && DECL_FUNCTION_CODE (node->decl) < BEGIN_CHKP_BUILTINS)))
665 if (chkp_instrumentable_p (node->decl))
666 chkp_maybe_create_clone (node->decl);
667 else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl),
668 node->decl)))
670 if (warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wchkp,
671 "function cannot be instrumented"))
672 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
677 /* Mark all aliases and thunks of functions with no instrumented
678 version as legacy function. */
679 FOR_EACH_DEFINED_FUNCTION (node)
681 if (!node->instrumentation_clone
682 && !node->instrumented_version
683 && (node->alias || node->thunk.thunk_p)
684 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
685 DECL_ATTRIBUTES (node->decl)
686 = tree_cons (get_identifier ("bnd_legacy"), NULL,
687 DECL_ATTRIBUTES (node->decl));
690 bitmap_obstack_release (NULL);
692 return 0;
695 /* In this pass we remove bodies of functions having
696 instrumented version. Functions with removed bodies
697 become a special kind of thunks to provide a connection
698 between calls to the original version and instrumented
699 function. */
701 static unsigned int
702 chkp_produce_thunks (bool early)
704 struct cgraph_node *node;
706 FOR_EACH_DEFINED_FUNCTION (node)
708 if (!node->instrumentation_clone
709 && node->instrumented_version
710 && gimple_has_body_p (node->decl)
711 && gimple_has_body_p (node->instrumented_version->decl)
712 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
713 || !early))
715 node->release_body ();
716 node->remove_callees ();
717 node->remove_all_references ();
719 node->thunk.thunk_p = true;
720 node->thunk.add_pointer_bounds_args = true;
721 node->create_edge (node->instrumented_version, NULL,
722 0, CGRAPH_FREQ_BASE);
723 node->create_reference (node->instrumented_version,
724 IPA_REF_CHKP, NULL);
725 /* Thunk shouldn't be a cdtor. */
726 DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
727 DECL_STATIC_DESTRUCTOR (node->decl) = 0;
731 /* Mark instrumentation clones created for aliases and thunks
732 as insttrumented so they could be removed as unreachable
733 now. */
734 if (!early)
736 FOR_EACH_DEFINED_FUNCTION (node)
738 if (node->instrumentation_clone
739 && (node->alias || node->thunk.thunk_p)
740 && !chkp_function_instrumented_p (node->decl))
741 chkp_function_mark_instrumented (node->decl);
745 return TODO_remove_functions;
748 const pass_data pass_data_ipa_chkp_versioning =
750 SIMPLE_IPA_PASS, /* type */
751 "chkp_versioning", /* name */
752 OPTGROUP_NONE, /* optinfo_flags */
753 TV_NONE, /* tv_id */
754 0, /* properties_required */
755 0, /* properties_provided */
756 0, /* properties_destroyed */
757 0, /* todo_flags_start */
758 0 /* todo_flags_finish */
761 const pass_data pass_data_ipa_chkp_early_produce_thunks =
763 SIMPLE_IPA_PASS, /* type */
764 "chkp_ecleanup", /* name */
765 OPTGROUP_NONE, /* optinfo_flags */
766 TV_NONE, /* tv_id */
767 0, /* properties_required */
768 0, /* properties_provided */
769 0, /* properties_destroyed */
770 0, /* todo_flags_start */
771 0 /* todo_flags_finish */
774 const pass_data pass_data_ipa_chkp_produce_thunks =
776 SIMPLE_IPA_PASS, /* type */
777 "chkp_cleanup", /* name */
778 OPTGROUP_NONE, /* optinfo_flags */
779 TV_NONE, /* tv_id */
780 0, /* properties_required */
781 0, /* properties_provided */
782 0, /* properties_destroyed */
783 0, /* todo_flags_start */
784 0 /* todo_flags_finish */
787 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
789 public:
790 pass_ipa_chkp_versioning (gcc::context *ctxt)
791 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
794 /* opt_pass methods: */
795 virtual opt_pass * clone ()
797 return new pass_ipa_chkp_versioning (m_ctxt);
800 virtual bool gate (function *)
802 return flag_check_pointer_bounds;
805 virtual unsigned int execute (function *)
807 return chkp_versioning ();
810 }; // class pass_ipa_chkp_versioning
812 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
814 public:
815 pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
816 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
819 /* opt_pass methods: */
820 virtual opt_pass * clone ()
822 return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
825 virtual bool gate (function *)
827 return flag_check_pointer_bounds;
830 virtual unsigned int execute (function *)
832 return chkp_produce_thunks (true);
835 }; // class pass_chkp_produce_thunks
837 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
839 public:
840 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
841 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
844 /* opt_pass methods: */
845 virtual opt_pass * clone ()
847 return new pass_ipa_chkp_produce_thunks (m_ctxt);
850 virtual bool gate (function *)
852 return flag_check_pointer_bounds;
855 virtual unsigned int execute (function *)
857 return chkp_produce_thunks (false);
860 }; // class pass_chkp_produce_thunks
862 simple_ipa_opt_pass *
863 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
865 return new pass_ipa_chkp_versioning (ctxt);
868 simple_ipa_opt_pass *
869 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
871 return new pass_ipa_chkp_early_produce_thunks (ctxt);
874 simple_ipa_opt_pass *
875 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
877 return new pass_ipa_chkp_produce_thunks (ctxt);