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
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
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/>. */
23 #include "coretypes.h"
28 #include "fold-const.h"
29 #include "stor-layout.h"
30 #include "tree-pass.h"
31 #include "stringpool.h"
33 #include "gimple-expr.h"
35 #include "hard-reg-set.h"
38 #include "tree-ssa-alias.h"
40 #include "basic-block.h"
43 #include "lto-streamer.h"
45 #include "tree-chkp.h"
46 #include "tree-inline.h"
49 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
51 In instrumented code each pointer is provided with bounds. For input
52 pointer parameters it means we also have bounds passed. For calls it
53 means we have additional bounds arguments for pointer arguments.
55 To have all IPA optimizations working correctly we have to express
56 dataflow between passed and received bounds explicitly via additional
57 entries in function declaration arguments list and in function type.
58 Since we may have both instrumented and not instrumented code at the
59 same time, we cannot replace all original functions with their
60 instrumented variants. Therefore we create clones (versions) instead.
62 Instrumentation clones creation is a separate IPA pass which is a part
63 of early local passes. Clones are created after SSA is built (because
64 instrumentation pass works on SSA) and before any transformations
65 which may change pointer flow and therefore lead to incorrect code
66 instrumentation (possibly causing false bounds check failures).
68 Instrumentation clones have pointer bounds arguments added right after
69 pointer arguments. Clones have assembler name of the original
70 function with suffix added. New assembler name is in transparent
71 alias chain with the original name. Thus we expect all calls to the
72 original and instrumented functions look similar in assembler.
74 During instrumentation versioning pass we create instrumented versions
75 of all function with body and also for all their aliases and thunks.
76 Clones for functions with no body are created on demand (usually
77 during call instrumentation).
79 Original and instrumented function nodes are connected with IPA
80 reference IPA_REF_CHKP. It is mostly done to have reachability
81 analysis working correctly. We may have no references to the
82 instrumented function in the code but it still should be counted
83 as reachable if the original function is reachable.
85 When original function bodies are not needed anymore we release
86 them and transform functions into a special kind of thunks. Each
87 thunk has a call edge to the instrumented version. These thunks
88 help to keep externally visible instrumented functions visible
89 when linker resolution files are used. Linker has no info about
90 connection between original and instrumented function and
91 therefore we may wrongly decide (due to difference in assembler
92 names) that instrumented function version is local and can be
95 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
96 #define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
98 /* Return 1 calls to FNDECL should be replaced with
99 a call to wrapper function. */
101 chkp_wrap_function (tree fndecl
)
103 if (!flag_chkp_use_wrappers
)
106 if (DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
)
108 switch (DECL_FUNCTION_CODE (fndecl
))
110 case BUILT_IN_STRLEN
:
111 case BUILT_IN_STRCPY
:
112 case BUILT_IN_STRNCPY
:
113 case BUILT_IN_STPCPY
:
114 case BUILT_IN_STPNCPY
:
115 case BUILT_IN_STRCAT
:
116 case BUILT_IN_STRNCAT
:
117 case BUILT_IN_MEMCPY
:
118 case BUILT_IN_MEMPCPY
:
119 case BUILT_IN_MEMSET
:
120 case BUILT_IN_MEMMOVE
:
122 case BUILT_IN_MALLOC
:
123 case BUILT_IN_CALLOC
:
124 case BUILT_IN_REALLOC
:
136 chkp_wrap_function_name (tree fndecl
)
138 gcc_assert (DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
);
140 switch (DECL_FUNCTION_CODE (fndecl
))
142 case BUILT_IN_STRLEN
:
143 return CHKP_WRAPPER_SYMBOL_PREFIX
"strlen";
144 case BUILT_IN_STRCPY
:
145 return CHKP_WRAPPER_SYMBOL_PREFIX
"strcpy";
146 case BUILT_IN_STRNCPY
:
147 return CHKP_WRAPPER_SYMBOL_PREFIX
"strncpy";
148 case BUILT_IN_STPCPY
:
149 return CHKP_WRAPPER_SYMBOL_PREFIX
"stpcpy";
150 case BUILT_IN_STPNCPY
:
151 return CHKP_WRAPPER_SYMBOL_PREFIX
"stpncpy";
152 case BUILT_IN_STRCAT
:
153 return CHKP_WRAPPER_SYMBOL_PREFIX
"strcat";
154 case BUILT_IN_STRNCAT
:
155 return CHKP_WRAPPER_SYMBOL_PREFIX
"strncat";
156 case BUILT_IN_MEMCPY
:
157 return CHKP_WRAPPER_SYMBOL_PREFIX
"memcpy";
158 case BUILT_IN_MEMPCPY
:
159 return CHKP_WRAPPER_SYMBOL_PREFIX
"mempcpy";
160 case BUILT_IN_MEMSET
:
161 return CHKP_WRAPPER_SYMBOL_PREFIX
"memset";
162 case BUILT_IN_MEMMOVE
:
163 return CHKP_WRAPPER_SYMBOL_PREFIX
"memmove";
165 return CHKP_WRAPPER_SYMBOL_PREFIX
"bzero";
166 case BUILT_IN_MALLOC
:
167 return CHKP_WRAPPER_SYMBOL_PREFIX
"malloc";
168 case BUILT_IN_CALLOC
:
169 return CHKP_WRAPPER_SYMBOL_PREFIX
"calloc";
170 case BUILT_IN_REALLOC
:
171 return CHKP_WRAPPER_SYMBOL_PREFIX
"realloc";
180 /* Build a clone of FNDECL with a modified name. */
183 chkp_build_instrumented_fndecl (tree fndecl
)
185 tree new_decl
= copy_node (fndecl
);
189 /* called_as_built_in checks DECL_NAME to identify calls to
190 builtins. We want instrumented calls to builtins to be
191 recognized by called_as_built_in. Therefore use original
192 DECL_NAME for cloning with no prefixes. */
193 s
= IDENTIFIER_POINTER (DECL_NAME (fndecl
));
195 DECL_NAME (new_decl
) = get_identifier (s
.c_str ());
197 /* References to the original and to the instrumented version
198 should look the same in the output assembly. And we cannot
199 use the same assembler name for the instrumented version
200 because it conflicts with decl merging algorithms in LTO.
201 Achieve the result by using transparent alias name for the
202 instrumented version. */
203 if (chkp_wrap_function(fndecl
))
205 new_name
= get_identifier (chkp_wrap_function_name (fndecl
));
206 DECL_VISIBILITY (new_decl
) = VISIBILITY_DEFAULT
;
210 s
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl
));
212 new_name
= get_identifier (s
.c_str ());
213 IDENTIFIER_TRANSPARENT_ALIAS (new_name
) = 1;
214 TREE_CHAIN (new_name
) = DECL_ASSEMBLER_NAME (fndecl
);
216 SET_DECL_ASSEMBLER_NAME (new_decl
, new_name
);
218 /* For functions with body versioning will make a copy of arguments.
219 For functions with no body we need to do it here. */
220 if (!gimple_has_body_p (fndecl
))
221 DECL_ARGUMENTS (new_decl
) = copy_list (DECL_ARGUMENTS (fndecl
));
223 /* We are going to modify attributes list and therefore should
225 DECL_ATTRIBUTES (new_decl
) = copy_list (DECL_ATTRIBUTES (fndecl
));
227 /* Change builtin function code. */
228 if (DECL_BUILT_IN (new_decl
))
230 gcc_assert (DECL_BUILT_IN_CLASS (new_decl
) == BUILT_IN_NORMAL
);
231 gcc_assert (DECL_FUNCTION_CODE (new_decl
) < BEGIN_CHKP_BUILTINS
);
232 DECL_FUNCTION_CODE (new_decl
)
233 = (enum built_in_function
)(DECL_FUNCTION_CODE (new_decl
)
234 + BEGIN_CHKP_BUILTINS
+ 1);
241 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
242 Integer operands are replaced with values according to
243 INDEXES map having LEN elements. For operands out of len
244 we just add DELTA. */
247 chkp_map_attr_arg_indexes (tree attrs
, const char *attr_name
,
248 unsigned *indexes
, int len
, int delta
)
250 tree attr
= lookup_attribute (attr_name
, attrs
);
256 TREE_VALUE (attr
) = copy_list (TREE_VALUE (attr
));
257 for (op
= TREE_VALUE (attr
); op
; op
= TREE_CHAIN (op
))
261 if (TREE_CODE (TREE_VALUE (op
)) != INTEGER_CST
)
264 idx
= TREE_INT_CST_LOW (TREE_VALUE (op
));
266 /* If idx exceeds indexes length then we just
267 keep it at the same distance from the last
272 idx
= indexes
[idx
- 1] + 1;
273 TREE_VALUE (op
) = build_int_cst (TREE_TYPE (TREE_VALUE (op
)), idx
);
277 /* Make a copy of function type ORIG_TYPE adding pointer
278 bounds as additional arguments. */
281 chkp_copy_function_type_adding_bounds (tree orig_type
)
284 tree arg_type
, attrs
;
285 unsigned len
= list_length (TYPE_ARG_TYPES (orig_type
));
286 unsigned *indexes
= XALLOCAVEC (unsigned, len
);
287 unsigned idx
= 0, new_idx
= 0;
289 for (arg_type
= TYPE_ARG_TYPES (orig_type
);
291 arg_type
= TREE_CHAIN (arg_type
))
292 if (TREE_VALUE (arg_type
) == void_type_node
)
294 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type
))
295 || pass_by_reference (NULL
, TYPE_MODE (TREE_VALUE (arg_type
)),
296 TREE_VALUE (arg_type
), true)
297 || chkp_type_has_pointer (TREE_VALUE (arg_type
)))
300 /* We may use original type if there are no bounds passed. */
304 type
= build_distinct_type_copy (orig_type
);
305 TYPE_ARG_TYPES (type
) = copy_list (TYPE_ARG_TYPES (type
));
307 for (arg_type
= TYPE_ARG_TYPES (type
);
309 arg_type
= TREE_CHAIN (arg_type
))
311 indexes
[idx
++] = new_idx
++;
313 /* pass_by_reference returns 1 for void type,
314 so check for it first. */
315 if (TREE_VALUE (arg_type
) == void_type_node
)
317 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type
))
318 || pass_by_reference (NULL
, TYPE_MODE (TREE_VALUE (arg_type
)),
319 TREE_VALUE (arg_type
), true))
321 tree new_type
= build_tree_list (NULL_TREE
,
322 pointer_bounds_type_node
);
323 TREE_CHAIN (new_type
) = TREE_CHAIN (arg_type
);
324 TREE_CHAIN (arg_type
) = new_type
;
326 arg_type
= TREE_CHAIN (arg_type
);
329 else if (chkp_type_has_pointer (TREE_VALUE (arg_type
)))
331 bitmap slots
= BITMAP_ALLOC (NULL
);
335 chkp_find_bound_slots (TREE_VALUE (arg_type
), slots
);
337 EXECUTE_IF_SET_IN_BITMAP (slots
, 0, bnd_no
, bi
)
339 tree new_type
= build_tree_list (NULL_TREE
,
340 pointer_bounds_type_node
);
341 TREE_CHAIN (new_type
) = TREE_CHAIN (arg_type
);
342 TREE_CHAIN (arg_type
) = new_type
;
344 arg_type
= TREE_CHAIN (arg_type
);
351 /* If function type has attribute with arg indexes then
352 we have to copy it fixing attribute ops. Map for
353 fixing is in indexes array. */
354 attrs
= TYPE_ATTRIBUTES (type
);
355 if (lookup_attribute ("nonnull", attrs
)
356 || lookup_attribute ("format", attrs
)
357 || lookup_attribute ("format_arg", attrs
))
359 int delta
= new_idx
- len
;
360 attrs
= copy_list (TYPE_ATTRIBUTES (type
));
361 chkp_map_attr_arg_indexes (attrs
, "nonnull", indexes
, len
, delta
);
362 chkp_map_attr_arg_indexes (attrs
, "format", indexes
, len
, delta
);
363 chkp_map_attr_arg_indexes (attrs
, "format_arg", indexes
, len
, delta
);
364 TYPE_ATTRIBUTES (type
) = attrs
;
370 /* For given function FNDECL add bounds arguments to arguments
374 chkp_add_bounds_params_to_function (tree fndecl
)
378 for (arg
= DECL_ARGUMENTS (fndecl
); arg
; arg
= DECL_CHAIN (arg
))
381 std::string new_name
= CHKP_BOUNDS_OF_SYMBOL_PREFIX
;
385 new_name
+= IDENTIFIER_POINTER (DECL_NAME (arg
));
389 snprintf (uid
, 25, "D.%u", DECL_UID (arg
));
393 new_arg
= build_decl (DECL_SOURCE_LOCATION (arg
), 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 (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
);
405 else if (chkp_type_has_pointer (TREE_TYPE (arg
)))
408 bitmap slots
= BITMAP_ALLOC (NULL
);
412 chkp_find_bound_slots (TREE_TYPE (arg
), slots
);
414 EXECUTE_IF_SET_IN_BITMAP (slots
, 0, bnd_no
, bi
)
416 std::string new_name
= CHKP_BOUNDS_OF_SYMBOL_PREFIX
;
420 if (DECL_NAME (orig_arg
))
421 new_name
+= IDENTIFIER_POINTER (DECL_NAME (orig_arg
));
424 snprintf (offs
, 25, "D.%u", DECL_UID (arg
));
427 snprintf (offs
, 25, "__%u", bnd_no
* POINTER_SIZE
/ BITS_PER_UNIT
);
429 new_arg
= build_decl (DECL_SOURCE_LOCATION (orig_arg
),
431 get_identifier (new_name
.c_str ()),
432 pointer_bounds_type_node
);
433 DECL_ARG_TYPE (new_arg
) = pointer_bounds_type_node
;
434 DECL_CONTEXT (new_arg
) = DECL_CONTEXT (orig_arg
);
435 DECL_ARTIFICIAL (new_arg
) = 1;
436 DECL_CHAIN (new_arg
) = DECL_CHAIN (arg
);
437 DECL_CHAIN (arg
) = new_arg
;
439 arg
= DECL_CHAIN (arg
);
445 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl
));
448 /* Return an instrumentation clone for builtin function
449 FNDECL. Create one if needed. */
452 chkp_maybe_clone_builtin_fndecl (tree fndecl
)
455 enum built_in_function fcode
= DECL_FUNCTION_CODE (fndecl
);
457 gcc_assert (DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
458 && fcode
< BEGIN_CHKP_BUILTINS
);
460 fcode
= (enum built_in_function
) (fcode
+ BEGIN_CHKP_BUILTINS
+ 1);
461 clone
= builtin_decl_explicit (fcode
);
465 clone
= chkp_build_instrumented_fndecl (fndecl
);
466 chkp_add_bounds_params_to_function (clone
);
468 gcc_assert (DECL_FUNCTION_CODE (clone
) == fcode
);
470 set_builtin_decl (fcode
, clone
, false);
475 /* Return 1 if function FNDECL should be instrumented. */
478 chkp_instrumentable_p (tree fndecl
)
480 struct function
*fn
= DECL_STRUCT_FUNCTION (fndecl
);
481 return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl
))
482 && (!flag_chkp_instrument_marked_only
483 || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl
)))
484 && (!fn
|| !copy_forbidden (fn
, fndecl
)));
487 /* Return clone created for instrumentation of NODE or NULL. */
490 chkp_maybe_create_clone (tree fndecl
)
492 cgraph_node
*node
= cgraph_node::get_create (fndecl
);
493 cgraph_node
*clone
= node
->instrumented_version
;
495 gcc_assert (!node
->instrumentation_clone
);
497 if (DECL_BUILT_IN (fndecl
)
498 && (DECL_BUILT_IN_CLASS (fndecl
) != BUILT_IN_NORMAL
499 || DECL_FUNCTION_CODE (fndecl
) >= BEGIN_CHKP_BUILTINS
))
502 clone
= node
->instrumented_version
;
504 /* Some instrumented builtin function calls may be optimized and
505 cgraph nodes may be removed as unreachable. Later optimizations
506 may generate new calls to removed functions and in this case
507 we have to recreate cgraph node. FUNCTION_DECL for instrumented
508 builtin still exists and should be reused in such case. */
509 if (DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
510 && fndecl
== builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl
))
513 enum built_in_function fncode
= DECL_FUNCTION_CODE (fndecl
);
516 fncode
= (enum built_in_function
) (fncode
+ BEGIN_CHKP_BUILTINS
+ 1);
517 new_decl
= builtin_decl_explicit (fncode
);
519 /* We've actually already created an instrumented clone once.
523 clone
= cgraph_node::get (new_decl
);
527 gcc_assert (!gimple_has_body_p (fndecl
));
528 clone
= cgraph_node::get_create (new_decl
);
529 clone
->externally_visible
= node
->externally_visible
;
530 clone
->local
= node
->local
;
531 clone
->address_taken
= node
->address_taken
;
532 clone
->thunk
= node
->thunk
;
533 clone
->alias
= node
->alias
;
534 clone
->weakref
= node
->weakref
;
535 clone
->cpp_implicit_alias
= node
->cpp_implicit_alias
;
536 clone
->orig_decl
= fndecl
;
537 clone
->instrumentation_clone
= true;
540 clone
->instrumented_version
= node
;
541 node
->instrumented_version
= clone
;
547 tree new_decl
= chkp_build_instrumented_fndecl (fndecl
);
548 struct cgraph_edge
*e
;
552 clone
= node
->create_version_clone (new_decl
, vNULL
, NULL
);
553 clone
->externally_visible
= node
->externally_visible
;
554 clone
->local
= node
->local
;
555 clone
->address_taken
= node
->address_taken
;
556 clone
->thunk
= node
->thunk
;
557 clone
->alias
= node
->alias
;
558 clone
->weakref
= node
->weakref
;
559 clone
->cpp_implicit_alias
= node
->cpp_implicit_alias
;
560 clone
->instrumented_version
= node
;
561 clone
->orig_decl
= fndecl
;
562 clone
->instrumentation_clone
= true;
563 node
->instrumented_version
= clone
;
565 if (gimple_has_body_p (fndecl
))
567 gcc_assert (chkp_instrumentable_p (fndecl
));
568 tree_function_versioning (fndecl
, new_decl
, NULL
, false,
569 NULL
, false, NULL
, NULL
);
570 clone
->lowered
= true;
573 /* New params are inserted after versioning because it
574 actually copies args list from the original decl. */
575 chkp_add_bounds_params_to_function (new_decl
);
577 /* Remember builtin fndecl. */
578 if (DECL_BUILT_IN_CLASS (clone
->decl
) == BUILT_IN_NORMAL
579 && fndecl
== builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl
)))
581 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone
->decl
)));
582 set_builtin_decl (DECL_FUNCTION_CODE (clone
->decl
),
586 /* Clones have the same comdat group as originals. */
587 if (node
->same_comdat_group
588 || (DECL_ONE_ONLY (node
->decl
)
589 && !DECL_EXTERNAL (node
->decl
)))
590 clone
->add_to_same_comdat_group (node
);
592 if (gimple_has_body_p (fndecl
))
593 symtab
->call_cgraph_insertion_hooks (clone
);
595 /* Clone all aliases. */
596 for (i
= 0; node
->iterate_direct_aliases (i
, ref
); i
++)
597 chkp_maybe_create_clone (ref
->referring
->decl
);
599 /* Clone all thunks. */
600 for (e
= node
->callers
; e
; e
= e
->next_caller
)
601 if (e
->caller
->thunk
.thunk_p
602 && !e
->caller
->thunk
.add_pointer_bounds_args
603 && !e
->caller
->instrumentation_clone
)
605 struct cgraph_node
*thunk
606 = chkp_maybe_create_clone (e
->caller
->decl
);
607 /* Redirect thunk clone edge to the node clone. */
608 thunk
->callees
->redirect_callee (clone
);
611 /* For aliases and thunks we should make sure target is cloned
612 to have proper references and edges. */
613 if (node
->thunk
.thunk_p
)
614 chkp_maybe_create_clone (node
->callees
->callee
->decl
);
615 else if (node
->alias
)
617 struct cgraph_node
*target
;
619 ref
= node
->ref_list
.first_reference ();
622 target
= chkp_maybe_create_clone (ref
->referred
->decl
);
623 clone
->create_reference (target
, IPA_REF_ALIAS
);
626 if (node
->alias_target
)
628 if (TREE_CODE (node
->alias_target
) == FUNCTION_DECL
)
630 target
= chkp_maybe_create_clone (node
->alias_target
);
631 clone
->alias_target
= target
->decl
;
634 clone
->alias_target
= node
->alias_target
;
638 /* Add IPA reference. It's main role is to keep instrumented
639 version reachable while original node is reachable. */
640 ref
= node
->create_reference (clone
, IPA_REF_CHKP
, NULL
);
646 /* Create clone for all functions to be instrumented. */
649 chkp_versioning (void)
651 struct cgraph_node
*node
;
654 bitmap_obstack_initialize (NULL
);
656 FOR_EACH_DEFINED_FUNCTION (node
)
658 if (!node
->instrumentation_clone
659 && !node
->instrumented_version
661 && !node
->thunk
.thunk_p
662 && (!DECL_BUILT_IN (node
->decl
)
663 || (DECL_BUILT_IN_CLASS (node
->decl
) == BUILT_IN_NORMAL
664 && DECL_FUNCTION_CODE (node
->decl
) < BEGIN_CHKP_BUILTINS
)))
666 if (chkp_instrumentable_p (node
->decl
))
667 chkp_maybe_create_clone (node
->decl
);
668 else if ((reason
= copy_forbidden (DECL_STRUCT_FUNCTION (node
->decl
),
671 if (warning_at (DECL_SOURCE_LOCATION (node
->decl
), OPT_Wchkp
,
672 "function cannot be instrumented"))
673 inform (DECL_SOURCE_LOCATION (node
->decl
), reason
, node
->decl
);
678 /* Mark all aliases and thunks of functions with no instrumented
679 version as legacy function. */
680 FOR_EACH_DEFINED_FUNCTION (node
)
682 if (!node
->instrumentation_clone
683 && !node
->instrumented_version
684 && (node
->alias
|| node
->thunk
.thunk_p
)
685 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node
->decl
)))
686 DECL_ATTRIBUTES (node
->decl
)
687 = tree_cons (get_identifier ("bnd_legacy"), NULL
,
688 DECL_ATTRIBUTES (node
->decl
));
691 bitmap_obstack_release (NULL
);
696 /* In this pass we remove bodies of functions having
697 instrumented version. Functions with removed bodies
698 become a special kind of thunks to provide a connection
699 between calls to the original version and instrumented
703 chkp_produce_thunks (bool early
)
705 struct cgraph_node
*node
;
707 FOR_EACH_DEFINED_FUNCTION (node
)
709 if (!node
->instrumentation_clone
710 && node
->instrumented_version
711 && gimple_has_body_p (node
->decl
)
712 && gimple_has_body_p (node
->instrumented_version
->decl
)
713 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node
->decl
))
716 node
->release_body ();
717 node
->remove_callees ();
718 node
->remove_all_references ();
720 node
->thunk
.thunk_p
= true;
721 node
->thunk
.add_pointer_bounds_args
= true;
722 node
->create_edge (node
->instrumented_version
, NULL
,
723 0, CGRAPH_FREQ_BASE
);
724 node
->create_reference (node
->instrumented_version
,
726 /* Thunk shouldn't be a cdtor. */
727 DECL_STATIC_CONSTRUCTOR (node
->decl
) = 0;
728 DECL_STATIC_DESTRUCTOR (node
->decl
) = 0;
732 /* Mark instrumentation clones created for aliases and thunks
733 as insttrumented so they could be removed as unreachable
737 FOR_EACH_DEFINED_FUNCTION (node
)
739 if (node
->instrumentation_clone
740 && (node
->alias
|| node
->thunk
.thunk_p
)
741 && !chkp_function_instrumented_p (node
->decl
))
742 chkp_function_mark_instrumented (node
->decl
);
746 return TODO_remove_functions
;
749 const pass_data pass_data_ipa_chkp_versioning
=
751 SIMPLE_IPA_PASS
, /* type */
752 "chkp_versioning", /* name */
753 OPTGROUP_NONE
, /* optinfo_flags */
755 0, /* properties_required */
756 0, /* properties_provided */
757 0, /* properties_destroyed */
758 0, /* todo_flags_start */
759 0 /* todo_flags_finish */
762 const pass_data pass_data_ipa_chkp_early_produce_thunks
=
764 SIMPLE_IPA_PASS
, /* type */
765 "chkp_ecleanup", /* name */
766 OPTGROUP_NONE
, /* optinfo_flags */
768 0, /* properties_required */
769 0, /* properties_provided */
770 0, /* properties_destroyed */
771 0, /* todo_flags_start */
772 0 /* todo_flags_finish */
775 const pass_data pass_data_ipa_chkp_produce_thunks
=
777 SIMPLE_IPA_PASS
, /* type */
778 "chkp_cleanup", /* name */
779 OPTGROUP_NONE
, /* optinfo_flags */
781 0, /* properties_required */
782 0, /* properties_provided */
783 0, /* properties_destroyed */
784 0, /* todo_flags_start */
785 0 /* todo_flags_finish */
788 class pass_ipa_chkp_versioning
: public simple_ipa_opt_pass
791 pass_ipa_chkp_versioning (gcc::context
*ctxt
)
792 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning
, ctxt
)
795 /* opt_pass methods: */
796 virtual opt_pass
* clone ()
798 return new pass_ipa_chkp_versioning (m_ctxt
);
801 virtual bool gate (function
*)
803 return flag_check_pointer_bounds
;
806 virtual unsigned int execute (function
*)
808 return chkp_versioning ();
811 }; // class pass_ipa_chkp_versioning
813 class pass_ipa_chkp_early_produce_thunks
: public simple_ipa_opt_pass
816 pass_ipa_chkp_early_produce_thunks (gcc::context
*ctxt
)
817 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks
, ctxt
)
820 /* opt_pass methods: */
821 virtual opt_pass
* clone ()
823 return new pass_ipa_chkp_early_produce_thunks (m_ctxt
);
826 virtual bool gate (function
*)
828 return flag_check_pointer_bounds
;
831 virtual unsigned int execute (function
*)
833 return chkp_produce_thunks (true);
836 }; // class pass_chkp_produce_thunks
838 class pass_ipa_chkp_produce_thunks
: public simple_ipa_opt_pass
841 pass_ipa_chkp_produce_thunks (gcc::context
*ctxt
)
842 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks
, ctxt
)
845 /* opt_pass methods: */
846 virtual opt_pass
* clone ()
848 return new pass_ipa_chkp_produce_thunks (m_ctxt
);
851 virtual bool gate (function
*)
853 return flag_check_pointer_bounds
;
856 virtual unsigned int execute (function
*)
858 return chkp_produce_thunks (false);
861 }; // class pass_chkp_produce_thunks
863 simple_ipa_opt_pass
*
864 make_pass_ipa_chkp_versioning (gcc::context
*ctxt
)
866 return new pass_ipa_chkp_versioning (ctxt
);
869 simple_ipa_opt_pass
*
870 make_pass_ipa_chkp_early_produce_thunks (gcc::context
*ctxt
)
872 return new pass_ipa_chkp_early_produce_thunks (ctxt
);
875 simple_ipa_opt_pass
*
876 make_pass_ipa_chkp_produce_thunks (gcc::context
*ctxt
)
878 return new pass_ipa_chkp_produce_thunks (ctxt
);