PR c++/84493
[official-gcc.git] / gcc / ipa-chkp.c
blobb38b542ccb0536e2c2018e0164ba8f2f746a5ceb
1 /* Pointer Bounds Checker IPA passes.
2 Copyright (C) 2014-2018 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"
37 #include "stringpool.h"
38 #include "attribs.h"
40 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
42 In instrumented code each pointer is provided with bounds. For input
43 pointer parameters it means we also have bounds passed. For calls it
44 means we have additional bounds arguments for pointer arguments.
46 To have all IPA optimizations working correctly we have to express
47 dataflow between passed and received bounds explicitly via additional
48 entries in function declaration arguments list and in function type.
49 Since we may have both instrumented and not instrumented code at the
50 same time, we cannot replace all original functions with their
51 instrumented variants. Therefore we create clones (versions) instead.
53 Instrumentation clones creation is a separate IPA pass which is a part
54 of early local passes. Clones are created after SSA is built (because
55 instrumentation pass works on SSA) and before any transformations
56 which may change pointer flow and therefore lead to incorrect code
57 instrumentation (possibly causing false bounds check failures).
59 Instrumentation clones have pointer bounds arguments added right after
60 pointer arguments. Clones have assembler name of the original
61 function with suffix added. New assembler name is in transparent
62 alias chain with the original name. Thus we expect all calls to the
63 original and instrumented functions look similar in assembler.
65 During instrumentation versioning pass we create instrumented versions
66 of all function with body and also for all their aliases and thunks.
67 Clones for functions with no body are created on demand (usually
68 during call instrumentation).
70 Original and instrumented function nodes are connected with IPA
71 reference IPA_REF_CHKP. It is mostly done to have reachability
72 analysis working correctly. We may have no references to the
73 instrumented function in the code but it still should be counted
74 as reachable if the original function is reachable.
76 When original function bodies are not needed anymore we release
77 them and transform functions into a special kind of thunks. Each
78 thunk has a call edge to the instrumented version. These thunks
79 help to keep externally visible instrumented functions visible
80 when linker resolution files are used. Linker has no info about
81 connection between original and instrumented function and
82 therefore we may wrongly decide (due to difference in assembler
83 names) that instrumented function version is local and can be
84 removed. */
86 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
87 #define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
89 /* Return 1 calls to FNDECL should be replaced with
90 a call to wrapper function. */
91 bool
92 chkp_wrap_function (tree fndecl)
94 if (!flag_chkp_use_wrappers)
95 return false;
97 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
99 switch (DECL_FUNCTION_CODE (fndecl))
101 case BUILT_IN_STRLEN:
102 case BUILT_IN_STRCPY:
103 case BUILT_IN_STRNCPY:
104 case BUILT_IN_STPCPY:
105 case BUILT_IN_STPNCPY:
106 case BUILT_IN_STRCAT:
107 case BUILT_IN_STRNCAT:
108 case BUILT_IN_MEMCPY:
109 case BUILT_IN_MEMPCPY:
110 case BUILT_IN_MEMSET:
111 case BUILT_IN_MEMMOVE:
112 case BUILT_IN_BZERO:
113 case BUILT_IN_MALLOC:
114 case BUILT_IN_CALLOC:
115 case BUILT_IN_REALLOC:
116 return 1;
118 default:
119 return 0;
123 return false;
126 static const char *
127 chkp_wrap_function_name (tree fndecl)
129 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL);
131 switch (DECL_FUNCTION_CODE (fndecl))
133 case BUILT_IN_STRLEN:
134 return CHKP_WRAPPER_SYMBOL_PREFIX "strlen";
135 case BUILT_IN_STRCPY:
136 return CHKP_WRAPPER_SYMBOL_PREFIX "strcpy";
137 case BUILT_IN_STRNCPY:
138 return CHKP_WRAPPER_SYMBOL_PREFIX "strncpy";
139 case BUILT_IN_STPCPY:
140 return CHKP_WRAPPER_SYMBOL_PREFIX "stpcpy";
141 case BUILT_IN_STPNCPY:
142 return CHKP_WRAPPER_SYMBOL_PREFIX "stpncpy";
143 case BUILT_IN_STRCAT:
144 return CHKP_WRAPPER_SYMBOL_PREFIX "strcat";
145 case BUILT_IN_STRNCAT:
146 return CHKP_WRAPPER_SYMBOL_PREFIX "strncat";
147 case BUILT_IN_MEMCPY:
148 return CHKP_WRAPPER_SYMBOL_PREFIX "memcpy";
149 case BUILT_IN_MEMPCPY:
150 return CHKP_WRAPPER_SYMBOL_PREFIX "mempcpy";
151 case BUILT_IN_MEMSET:
152 return CHKP_WRAPPER_SYMBOL_PREFIX "memset";
153 case BUILT_IN_MEMMOVE:
154 return CHKP_WRAPPER_SYMBOL_PREFIX "memmove";
155 case BUILT_IN_BZERO:
156 return CHKP_WRAPPER_SYMBOL_PREFIX "bzero";
157 case BUILT_IN_MALLOC:
158 return CHKP_WRAPPER_SYMBOL_PREFIX "malloc";
159 case BUILT_IN_CALLOC:
160 return CHKP_WRAPPER_SYMBOL_PREFIX "calloc";
161 case BUILT_IN_REALLOC:
162 return CHKP_WRAPPER_SYMBOL_PREFIX "realloc";
164 default:
165 gcc_unreachable ();
168 return "";
171 /* Build a clone of FNDECL with a modified name. */
173 static tree
174 chkp_build_instrumented_fndecl (tree fndecl)
176 tree new_decl = copy_node (fndecl);
177 tree new_name;
178 std::string s;
180 /* called_as_built_in checks DECL_NAME to identify calls to
181 builtins. We want instrumented calls to builtins to be
182 recognized by called_as_built_in. Therefore use original
183 DECL_NAME for cloning with no prefixes. */
184 s = IDENTIFIER_POINTER (DECL_NAME (fndecl));
185 s += ".chkp";
186 DECL_NAME (new_decl) = get_identifier (s.c_str ());
188 /* References to the original and to the instrumented version
189 should look the same in the output assembly. And we cannot
190 use the same assembler name for the instrumented version
191 because it conflicts with decl merging algorithms in LTO.
192 Achieve the result by using transparent alias name for the
193 instrumented version. */
194 if (chkp_wrap_function(fndecl))
196 new_name = get_identifier (chkp_wrap_function_name (fndecl));
197 DECL_VISIBILITY (new_decl) = VISIBILITY_DEFAULT;
199 else
201 s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
202 s += ".chkp";
203 new_name = get_identifier (s.c_str ());
204 IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
205 TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
207 SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
209 /* For functions with body versioning will make a copy of arguments.
210 For functions with no body we need to do it here. */
211 if (!gimple_has_body_p (fndecl))
213 tree arg;
215 DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
216 for (arg = DECL_ARGUMENTS (new_decl); arg; arg = DECL_CHAIN (arg))
217 DECL_CONTEXT (arg) = new_decl;
220 /* We are going to modify attributes list and therefore should
221 make own copy. */
222 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
224 /* Change builtin function code. */
225 if (DECL_BUILT_IN (new_decl))
227 gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL);
228 gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS);
229 DECL_FUNCTION_CODE (new_decl)
230 = (enum built_in_function)(DECL_FUNCTION_CODE (new_decl)
231 + BEGIN_CHKP_BUILTINS + 1);
234 return new_decl;
238 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
239 Integer operands are replaced with values according to
240 INDEXES map having LEN elements. For operands out of len
241 we just add DELTA. */
243 static void
244 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
245 unsigned *indexes, int len, int delta)
247 tree attr = lookup_attribute (attr_name, attrs);
248 tree op;
250 if (!attr)
251 return;
253 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
254 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
256 int idx;
258 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
259 continue;
261 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
263 /* If idx exceeds indexes length then we just
264 keep it at the same distance from the last
265 known arg. */
266 if (idx > len)
267 idx += delta;
268 else
269 idx = indexes[idx - 1] + 1;
270 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
274 /* Make a copy of function type ORIG_TYPE adding pointer
275 bounds as additional arguments. */
277 tree
278 chkp_copy_function_type_adding_bounds (tree orig_type)
280 tree type;
281 tree arg_type, attrs;
282 unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
283 unsigned *indexes = XALLOCAVEC (unsigned, len);
284 unsigned idx = 0, new_idx = 0;
286 for (arg_type = TYPE_ARG_TYPES (orig_type);
287 arg_type;
288 arg_type = TREE_CHAIN (arg_type))
289 if (TREE_VALUE (arg_type) == void_type_node)
290 continue;
291 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
292 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
293 TREE_VALUE (arg_type), true)
294 || chkp_type_has_pointer (TREE_VALUE (arg_type)))
295 break;
297 /* We may use original type if there are no bounds passed. */
298 if (!arg_type)
299 return orig_type;
301 type = build_distinct_type_copy (orig_type);
302 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
304 for (arg_type = TYPE_ARG_TYPES (type);
305 arg_type;
306 arg_type = TREE_CHAIN (arg_type))
308 indexes[idx++] = new_idx++;
310 /* pass_by_reference returns 1 for void type,
311 so check for it first. */
312 if (TREE_VALUE (arg_type) == void_type_node)
313 continue;
314 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
315 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
316 TREE_VALUE (arg_type), true))
318 tree new_type = build_tree_list (NULL_TREE,
319 pointer_bounds_type_node);
320 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
321 TREE_CHAIN (arg_type) = new_type;
323 arg_type = TREE_CHAIN (arg_type);
324 new_idx++;
326 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
328 bitmap slots = BITMAP_ALLOC (NULL);
329 bitmap_iterator bi;
330 unsigned bnd_no;
332 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
334 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
336 tree new_type = build_tree_list (NULL_TREE,
337 pointer_bounds_type_node);
338 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
339 TREE_CHAIN (arg_type) = new_type;
341 arg_type = TREE_CHAIN (arg_type);
342 new_idx++;
344 BITMAP_FREE (slots);
348 /* If function type has attribute with arg indexes then
349 we have to copy it fixing attribute ops. Map for
350 fixing is in indexes array. */
351 attrs = TYPE_ATTRIBUTES (type);
352 if (lookup_attribute ("nonnull", attrs)
353 || lookup_attribute ("format", attrs)
354 || lookup_attribute ("format_arg", attrs))
356 int delta = new_idx - len;
357 attrs = copy_list (TYPE_ATTRIBUTES (type));
358 chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
359 chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
360 chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
361 TYPE_ATTRIBUTES (type) = attrs;
364 return type;
367 /* For given function FNDECL add bounds arguments to arguments
368 list. */
370 static void
371 chkp_add_bounds_params_to_function (tree fndecl)
373 tree arg;
375 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
376 if (BOUNDED_P (arg))
378 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
379 tree new_arg;
381 if (DECL_NAME (arg))
382 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
383 else
385 char uid[25];
386 snprintf (uid, 25, "D.%u", DECL_UID (arg));
387 new_name += uid;
390 new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
391 get_identifier (new_name.c_str ()),
392 pointer_bounds_type_node);
393 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
394 DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
395 DECL_ARTIFICIAL (new_arg) = 1;
396 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
397 DECL_CHAIN (arg) = new_arg;
399 arg = DECL_CHAIN (arg);
402 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
404 tree orig_arg = arg;
405 bitmap slots = BITMAP_ALLOC (NULL);
406 bitmap_iterator bi;
407 unsigned bnd_no;
409 chkp_find_bound_slots (TREE_TYPE (arg), slots);
411 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
413 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
414 tree new_arg;
415 char offs[25];
417 if (DECL_NAME (orig_arg))
418 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
419 else
421 snprintf (offs, 25, "D.%u", DECL_UID (arg));
422 new_name += offs;
424 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
426 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
427 PARM_DECL,
428 get_identifier (new_name.c_str ()),
429 pointer_bounds_type_node);
430 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
431 DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
432 DECL_ARTIFICIAL (new_arg) = 1;
433 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
434 DECL_CHAIN (arg) = new_arg;
436 arg = DECL_CHAIN (arg);
438 BITMAP_FREE (slots);
441 TREE_TYPE (fndecl) =
442 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
445 /* Return an instrumentation clone for builtin function
446 FNDECL. Create one if needed. */
448 tree
449 chkp_maybe_clone_builtin_fndecl (tree fndecl)
451 tree clone;
452 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
454 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
455 && fcode < BEGIN_CHKP_BUILTINS);
457 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
458 clone = builtin_decl_explicit (fcode);
459 if (clone)
460 return clone;
462 clone = chkp_build_instrumented_fndecl (fndecl);
463 chkp_add_bounds_params_to_function (clone);
465 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
467 set_builtin_decl (fcode, clone, false);
469 return clone;
472 /* Return 1 if function FNDECL should be instrumented. */
474 bool
475 chkp_instrumentable_p (tree fndecl)
477 struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
478 return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
479 && (!flag_chkp_instrument_marked_only
480 || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl)))
481 && (!fn || !copy_forbidden (fn)));
484 /* Return clone created for instrumentation of NODE or NULL. */
486 cgraph_node *
487 chkp_maybe_create_clone (tree fndecl)
489 cgraph_node *node = cgraph_node::get_create (fndecl);
490 cgraph_node *clone = node->instrumented_version;
492 gcc_assert (!node->instrumentation_clone);
494 if (DECL_BUILT_IN (fndecl)
495 && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
496 || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
497 return NULL;
499 clone = node->instrumented_version;
501 /* Some instrumented builtin function calls may be optimized and
502 cgraph nodes may be removed as unreachable. Later optimizations
503 may generate new calls to removed functions and in this case
504 we have to recreate cgraph node. FUNCTION_DECL for instrumented
505 builtin still exists and should be reused in such case. */
506 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
507 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))
508 && !clone)
510 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
511 tree new_decl;
513 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
514 new_decl = builtin_decl_explicit (fncode);
516 /* We've actually already created an instrumented clone once.
517 Restore it. */
518 if (new_decl)
520 clone = cgraph_node::get (new_decl);
522 if (!clone)
524 gcc_assert (!gimple_has_body_p (fndecl));
525 clone = cgraph_node::get_create (new_decl);
526 clone->externally_visible = node->externally_visible;
527 clone->local = node->local;
528 clone->address_taken = node->address_taken;
529 clone->thunk = node->thunk;
530 clone->alias = node->alias;
531 clone->weakref = node->weakref;
532 clone->cpp_implicit_alias = node->cpp_implicit_alias;
533 clone->orig_decl = fndecl;
534 clone->instrumentation_clone = true;
537 clone->instrumented_version = node;
538 node->instrumented_version = clone;
542 if (!clone)
544 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
545 struct cgraph_edge *e;
546 struct ipa_ref *ref;
547 int i;
549 clone = node->create_version_clone (new_decl, vNULL, NULL);
550 clone->externally_visible = node->externally_visible;
551 clone->local = node->local;
552 clone->address_taken = node->address_taken;
553 clone->thunk = node->thunk;
554 clone->alias = node->alias;
555 clone->weakref = node->weakref;
556 clone->cpp_implicit_alias = node->cpp_implicit_alias;
557 clone->instrumented_version = node;
558 clone->orig_decl = fndecl;
559 clone->instrumentation_clone = true;
560 node->instrumented_version = clone;
562 if (gimple_has_body_p (fndecl))
564 gcc_assert (chkp_instrumentable_p (fndecl));
565 tree_function_versioning (fndecl, new_decl, NULL, false,
566 NULL, false, NULL, NULL);
567 clone->lowered = true;
570 /* New params are inserted after versioning because it
571 actually copies args list from the original decl. */
572 chkp_add_bounds_params_to_function (new_decl);
574 /* Remember builtin fndecl. */
575 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
576 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
578 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
579 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
580 clone->decl, false);
583 /* Clones have the same comdat group as originals. */
584 if (node->same_comdat_group
585 || (DECL_ONE_ONLY (node->decl)
586 && !DECL_EXTERNAL (node->decl)))
587 clone->add_to_same_comdat_group (node);
589 if (gimple_has_body_p (fndecl))
590 symtab->call_cgraph_insertion_hooks (clone);
592 /* Clone all aliases. */
593 for (i = 0; node->iterate_direct_aliases (i, ref); i++)
594 chkp_maybe_create_clone (ref->referring->decl);
596 /* Clone all thunks. */
597 for (e = node->callers; e; e = e->next_caller)
598 if (e->caller->thunk.thunk_p
599 && !e->caller->thunk.add_pointer_bounds_args
600 && !e->caller->instrumentation_clone)
602 struct cgraph_node *thunk
603 = chkp_maybe_create_clone (e->caller->decl);
604 /* Redirect thunk clone edge to the node clone. */
605 thunk->callees->redirect_callee (clone);
608 /* For aliases and thunks we should make sure target is cloned
609 to have proper references and edges. */
610 if (node->thunk.thunk_p)
611 chkp_maybe_create_clone (node->callees->callee->decl);
612 else if (node->alias)
614 struct cgraph_node *target;
616 ref = node->ref_list.first_reference ();
617 if (ref)
619 target = chkp_maybe_create_clone (ref->referred->decl);
620 clone->create_reference (target, IPA_REF_ALIAS);
623 if (node->alias_target)
625 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
627 target = chkp_maybe_create_clone (node->alias_target);
628 clone->alias_target = target->decl;
630 else
631 clone->alias_target = node->alias_target;
635 /* Add IPA reference. It's main role is to keep instrumented
636 version reachable while original node is reachable. */
637 ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
640 return clone;
643 /* Create clone for all functions to be instrumented. */
645 static unsigned int
646 chkp_versioning (void)
648 struct cgraph_node *node;
649 const char *reason;
651 bitmap_obstack_initialize (NULL);
653 FOR_EACH_DEFINED_FUNCTION (node)
655 tree decl = node->decl;
656 if (!node->instrumentation_clone
657 && !node->instrumented_version
658 && !node->alias
659 && !node->thunk.thunk_p
660 && (!DECL_BUILT_IN (decl)
661 || (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
662 && DECL_FUNCTION_CODE (decl) < BEGIN_CHKP_BUILTINS)))
664 if (chkp_instrumentable_p (decl))
665 chkp_maybe_create_clone (decl);
666 else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (decl))))
668 if (warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wchkp,
669 "function cannot be instrumented"))
670 inform (DECL_SOURCE_LOCATION (decl), reason, decl);
675 /* Mark all aliases and thunks of functions with no instrumented
676 version as legacy function. */
677 FOR_EACH_DEFINED_FUNCTION (node)
679 if (!node->instrumentation_clone
680 && !node->instrumented_version
681 && (node->alias || node->thunk.thunk_p)
682 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
683 DECL_ATTRIBUTES (node->decl)
684 = tree_cons (get_identifier ("bnd_legacy"), NULL,
685 DECL_ATTRIBUTES (node->decl));
688 bitmap_obstack_release (NULL);
690 return 0;
693 /* In this pass we remove bodies of functions having
694 instrumented version. Functions with removed bodies
695 become a special kind of thunks to provide a connection
696 between calls to the original version and instrumented
697 function. */
699 static unsigned int
700 chkp_produce_thunks (bool early)
702 struct cgraph_node *node;
704 FOR_EACH_DEFINED_FUNCTION (node)
706 if (!node->instrumentation_clone
707 && node->instrumented_version
708 && gimple_has_body_p (node->decl)
709 && gimple_has_body_p (node->instrumented_version->decl)
710 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
711 || !early))
713 node->release_body ();
714 node->remove_callees ();
715 node->remove_all_references ();
717 node->thunk.thunk_p = true;
718 node->thunk.add_pointer_bounds_args = true;
719 node->create_edge (node->instrumented_version, NULL,
720 node->count);
721 node->create_reference (node->instrumented_version,
722 IPA_REF_CHKP, NULL);
723 /* Thunk shouldn't be a cdtor. */
724 DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
725 DECL_STATIC_DESTRUCTOR (node->decl) = 0;
729 /* Mark instrumentation clones created for aliases and thunks
730 as insttrumented so they could be removed as unreachable
731 now. */
732 if (!early)
734 FOR_EACH_DEFINED_FUNCTION (node)
736 if (node->instrumentation_clone
737 && (node->alias || node->thunk.thunk_p)
738 && !chkp_function_instrumented_p (node->decl))
739 chkp_function_mark_instrumented (node->decl);
743 return TODO_remove_functions;
746 const pass_data pass_data_ipa_chkp_versioning =
748 SIMPLE_IPA_PASS, /* type */
749 "chkp_versioning", /* name */
750 OPTGROUP_NONE, /* optinfo_flags */
751 TV_NONE, /* tv_id */
752 0, /* properties_required */
753 0, /* properties_provided */
754 0, /* properties_destroyed */
755 0, /* todo_flags_start */
756 0 /* todo_flags_finish */
759 const pass_data pass_data_ipa_chkp_early_produce_thunks =
761 SIMPLE_IPA_PASS, /* type */
762 "chkp_ecleanup", /* name */
763 OPTGROUP_NONE, /* optinfo_flags */
764 TV_NONE, /* tv_id */
765 0, /* properties_required */
766 0, /* properties_provided */
767 0, /* properties_destroyed */
768 0, /* todo_flags_start */
769 0 /* todo_flags_finish */
772 const pass_data pass_data_ipa_chkp_produce_thunks =
774 SIMPLE_IPA_PASS, /* type */
775 "chkp_cleanup", /* name */
776 OPTGROUP_NONE, /* optinfo_flags */
777 TV_NONE, /* tv_id */
778 0, /* properties_required */
779 0, /* properties_provided */
780 0, /* properties_destroyed */
781 0, /* todo_flags_start */
782 0 /* todo_flags_finish */
785 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
787 public:
788 pass_ipa_chkp_versioning (gcc::context *ctxt)
789 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
792 /* opt_pass methods: */
793 virtual opt_pass * clone ()
795 return new pass_ipa_chkp_versioning (m_ctxt);
798 virtual bool gate (function *)
800 return flag_check_pointer_bounds;
803 virtual unsigned int execute (function *)
805 return chkp_versioning ();
808 }; // class pass_ipa_chkp_versioning
810 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
812 public:
813 pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
814 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
817 /* opt_pass methods: */
818 virtual opt_pass * clone ()
820 return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
823 virtual bool gate (function *)
825 return flag_check_pointer_bounds;
828 virtual unsigned int execute (function *)
830 return chkp_produce_thunks (true);
833 }; // class pass_chkp_produce_thunks
835 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
837 public:
838 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
839 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
842 /* opt_pass methods: */
843 virtual opt_pass * clone ()
845 return new pass_ipa_chkp_produce_thunks (m_ctxt);
848 virtual bool gate (function *)
850 return flag_check_pointer_bounds;
853 virtual unsigned int execute (function *)
855 return chkp_produce_thunks (false);
858 }; // class pass_chkp_produce_thunks
860 simple_ipa_opt_pass *
861 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
863 return new pass_ipa_chkp_versioning (ctxt);
866 simple_ipa_opt_pass *
867 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
869 return new pass_ipa_chkp_early_produce_thunks (ctxt);
872 simple_ipa_opt_pass *
873 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
875 return new pass_ipa_chkp_produce_thunks (ctxt);