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"
37 #include "tree-ssa-alias.h"
39 #include "basic-block.h"
42 #include "lto-streamer.h"
44 #include "tree-chkp.h"
45 #include "tree-inline.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
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. */
100 chkp_wrap_function (tree fndecl
)
102 if (!flag_chkp_use_wrappers
)
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
:
121 case BUILT_IN_MALLOC
:
122 case BUILT_IN_CALLOC
:
123 case BUILT_IN_REALLOC
:
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";
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";
179 /* Build a clone of FNDECL with a modified name. */
182 chkp_build_instrumented_fndecl (tree fndecl
)
184 tree new_decl
= copy_node (fndecl
);
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
));
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
;
209 s
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl
));
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
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);
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. */
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
);
255 TREE_VALUE (attr
) = copy_list (TREE_VALUE (attr
));
256 for (op
= TREE_VALUE (attr
); op
; op
= TREE_CHAIN (op
))
260 if (TREE_CODE (TREE_VALUE (op
)) != INTEGER_CST
)
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
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. */
280 chkp_copy_function_type_adding_bounds (tree orig_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
);
290 arg_type
= TREE_CHAIN (arg_type
))
291 if (TREE_VALUE (arg_type
) == void_type_node
)
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
)))
299 /* We may use original type if there are no bounds passed. */
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
);
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
)
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
);
328 else if (chkp_type_has_pointer (TREE_VALUE (arg_type
)))
330 bitmap slots
= BITMAP_ALLOC (NULL
);
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
);
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
;
369 /* For given function FNDECL add bounds arguments to arguments
373 chkp_add_bounds_params_to_function (tree fndecl
)
377 for (arg
= DECL_ARGUMENTS (fndecl
); arg
; arg
= DECL_CHAIN (arg
))
380 std::string new_name
= CHKP_BOUNDS_OF_SYMBOL_PREFIX
;
384 new_name
+= IDENTIFIER_POINTER (DECL_NAME (arg
));
388 snprintf (uid
, 25, "D.%u", DECL_UID (arg
));
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
)))
407 bitmap slots
= BITMAP_ALLOC (NULL
);
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
;
419 if (DECL_NAME (orig_arg
))
420 new_name
+= IDENTIFIER_POINTER (DECL_NAME (orig_arg
));
423 snprintf (offs
, 25, "D.%u", DECL_UID (arg
));
426 snprintf (offs
, 25, "__%u", bnd_no
* POINTER_SIZE
/ BITS_PER_UNIT
);
428 new_arg
= build_decl (DECL_SOURCE_LOCATION (orig_arg
),
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
);
444 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl
));
447 /* Return an instrumentation clone for builtin function
448 FNDECL. Create one if needed. */
451 chkp_maybe_clone_builtin_fndecl (tree fndecl
)
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
);
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);
474 /* Return 1 if function FNDECL should be instrumented. */
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. */
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
))
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
))
512 enum built_in_function fncode
= DECL_FUNCTION_CODE (fndecl
);
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.
522 clone
= cgraph_node::get (new_decl
);
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
;
546 tree new_decl
= chkp_build_instrumented_fndecl (fndecl
);
547 struct cgraph_edge
*e
;
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 /* If function will not be instrumented, then it's instrumented
567 version is a thunk for the original. */
568 if (!chkp_instrumentable_p (fndecl
))
570 clone
->remove_callees ();
571 clone
->remove_all_references ();
572 clone
->thunk
.thunk_p
= true;
573 clone
->thunk
.add_pointer_bounds_args
= true;
574 clone
->create_edge (node
, NULL
, 0, CGRAPH_FREQ_BASE
);
575 /* Thunk shouldn't be a cdtor. */
576 DECL_STATIC_CONSTRUCTOR (clone
->decl
) = 0;
577 DECL_STATIC_DESTRUCTOR (clone
->decl
) = 0;
581 tree_function_versioning (fndecl
, new_decl
, NULL
, false,
582 NULL
, false, NULL
, NULL
);
583 clone
->lowered
= true;
587 /* New params are inserted after versioning because it
588 actually copies args list from the original decl. */
589 chkp_add_bounds_params_to_function (new_decl
);
591 /* Remember builtin fndecl. */
592 if (DECL_BUILT_IN_CLASS (clone
->decl
) == BUILT_IN_NORMAL
593 && fndecl
== builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl
)))
595 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone
->decl
)));
596 set_builtin_decl (DECL_FUNCTION_CODE (clone
->decl
),
600 /* Clones have the same comdat group as originals. */
601 if (node
->same_comdat_group
602 || (DECL_ONE_ONLY (node
->decl
)
603 && !DECL_EXTERNAL (node
->decl
)))
604 clone
->add_to_same_comdat_group (node
);
606 if (gimple_has_body_p (fndecl
))
607 symtab
->call_cgraph_insertion_hooks (clone
);
609 /* Clone all aliases. */
610 for (i
= 0; node
->iterate_direct_aliases (i
, ref
); i
++)
611 chkp_maybe_create_clone (ref
->referring
->decl
);
613 /* Clone all thunks. */
614 for (e
= node
->callers
; e
; e
= e
->next_caller
)
615 if (e
->caller
->thunk
.thunk_p
616 && !e
->caller
->thunk
.add_pointer_bounds_args
617 && !e
->caller
->instrumentation_clone
)
619 struct cgraph_node
*thunk
620 = chkp_maybe_create_clone (e
->caller
->decl
);
621 /* Redirect thunk clone edge to the node clone. */
622 thunk
->callees
->redirect_callee (clone
);
625 /* For aliases and thunks we should make sure target is cloned
626 to have proper references and edges. */
627 if (node
->thunk
.thunk_p
)
628 chkp_maybe_create_clone (node
->callees
->callee
->decl
);
629 else if (node
->alias
)
631 struct cgraph_node
*target
;
633 ref
= node
->ref_list
.first_reference ();
636 target
= chkp_maybe_create_clone (ref
->referred
->decl
);
637 clone
->create_reference (target
, IPA_REF_ALIAS
);
640 if (node
->alias_target
)
642 if (TREE_CODE (node
->alias_target
) == FUNCTION_DECL
)
644 target
= chkp_maybe_create_clone (node
->alias_target
);
645 clone
->alias_target
= target
->decl
;
648 clone
->alias_target
= node
->alias_target
;
652 /* Add IPA reference. It's main role is to keep instrumented
653 version reachable while original node is reachable. */
654 ref
= node
->create_reference (clone
, IPA_REF_CHKP
, NULL
);
660 /* Create clone for all functions to be instrumented. */
663 chkp_versioning (void)
665 struct cgraph_node
*node
;
668 bitmap_obstack_initialize (NULL
);
670 FOR_EACH_DEFINED_FUNCTION (node
)
672 if (!node
->instrumentation_clone
673 && !node
->instrumented_version
675 && !node
->thunk
.thunk_p
676 && (!DECL_BUILT_IN (node
->decl
)
677 || (DECL_BUILT_IN_CLASS (node
->decl
) == BUILT_IN_NORMAL
678 && DECL_FUNCTION_CODE (node
->decl
) < BEGIN_CHKP_BUILTINS
)))
680 if (chkp_instrumentable_p (node
->decl
))
681 chkp_maybe_create_clone (node
->decl
);
682 else if ((reason
= copy_forbidden (DECL_STRUCT_FUNCTION (node
->decl
),
685 if (warning_at (DECL_SOURCE_LOCATION (node
->decl
), OPT_Wchkp
,
686 "function cannot be instrumented"))
687 inform (DECL_SOURCE_LOCATION (node
->decl
), reason
, node
->decl
);
692 /* Mark all aliases and thunks of functions with no instrumented
693 version as legacy function. */
694 FOR_EACH_DEFINED_FUNCTION (node
)
696 if (!node
->instrumentation_clone
697 && !node
->instrumented_version
698 && (node
->alias
|| node
->thunk
.thunk_p
)
699 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node
->decl
)))
700 DECL_ATTRIBUTES (node
->decl
)
701 = tree_cons (get_identifier ("bnd_legacy"), NULL
,
702 DECL_ATTRIBUTES (node
->decl
));
705 bitmap_obstack_release (NULL
);
710 /* In this pass we remove bodies of functions having
711 instrumented version. Functions with removed bodies
712 become a special kind of thunks to provide a connection
713 between calls to the original version and instrumented
717 chkp_produce_thunks (bool early
)
719 struct cgraph_node
*node
;
721 FOR_EACH_DEFINED_FUNCTION (node
)
723 if (!node
->instrumentation_clone
724 && node
->instrumented_version
725 && gimple_has_body_p (node
->decl
)
726 && gimple_has_body_p (node
->instrumented_version
->decl
)
727 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node
->decl
))
730 node
->release_body ();
731 node
->remove_callees ();
732 node
->remove_all_references ();
734 node
->thunk
.thunk_p
= true;
735 node
->thunk
.add_pointer_bounds_args
= true;
736 node
->create_edge (node
->instrumented_version
, NULL
,
737 0, CGRAPH_FREQ_BASE
);
738 node
->create_reference (node
->instrumented_version
,
740 /* Thunk shouldn't be a cdtor. */
741 DECL_STATIC_CONSTRUCTOR (node
->decl
) = 0;
742 DECL_STATIC_DESTRUCTOR (node
->decl
) = 0;
746 /* Mark instrumentation clones created for aliases and thunks
747 as insttrumented so they could be removed as unreachable
751 FOR_EACH_DEFINED_FUNCTION (node
)
753 if (node
->instrumentation_clone
754 && (node
->alias
|| node
->thunk
.thunk_p
)
755 && !chkp_function_instrumented_p (node
->decl
))
756 chkp_function_mark_instrumented (node
->decl
);
760 return TODO_remove_functions
;
763 const pass_data pass_data_ipa_chkp_versioning
=
765 SIMPLE_IPA_PASS
, /* type */
766 "chkp_versioning", /* name */
767 OPTGROUP_NONE
, /* optinfo_flags */
769 0, /* properties_required */
770 0, /* properties_provided */
771 0, /* properties_destroyed */
772 0, /* todo_flags_start */
773 0 /* todo_flags_finish */
776 const pass_data pass_data_ipa_chkp_early_produce_thunks
=
778 SIMPLE_IPA_PASS
, /* type */
779 "chkp_ecleanup", /* name */
780 OPTGROUP_NONE
, /* optinfo_flags */
782 0, /* properties_required */
783 0, /* properties_provided */
784 0, /* properties_destroyed */
785 0, /* todo_flags_start */
786 0 /* todo_flags_finish */
789 const pass_data pass_data_ipa_chkp_produce_thunks
=
791 SIMPLE_IPA_PASS
, /* type */
792 "chkp_cleanup", /* name */
793 OPTGROUP_NONE
, /* optinfo_flags */
795 0, /* properties_required */
796 0, /* properties_provided */
797 0, /* properties_destroyed */
798 0, /* todo_flags_start */
799 0 /* todo_flags_finish */
802 class pass_ipa_chkp_versioning
: public simple_ipa_opt_pass
805 pass_ipa_chkp_versioning (gcc::context
*ctxt
)
806 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning
, ctxt
)
809 /* opt_pass methods: */
810 virtual opt_pass
* clone ()
812 return new pass_ipa_chkp_versioning (m_ctxt
);
815 virtual bool gate (function
*)
817 return flag_check_pointer_bounds
;
820 virtual unsigned int execute (function
*)
822 return chkp_versioning ();
825 }; // class pass_ipa_chkp_versioning
827 class pass_ipa_chkp_early_produce_thunks
: public simple_ipa_opt_pass
830 pass_ipa_chkp_early_produce_thunks (gcc::context
*ctxt
)
831 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks
, ctxt
)
834 /* opt_pass methods: */
835 virtual opt_pass
* clone ()
837 return new pass_ipa_chkp_early_produce_thunks (m_ctxt
);
840 virtual bool gate (function
*)
842 return flag_check_pointer_bounds
;
845 virtual unsigned int execute (function
*)
847 return chkp_produce_thunks (true);
850 }; // class pass_chkp_produce_thunks
852 class pass_ipa_chkp_produce_thunks
: public simple_ipa_opt_pass
855 pass_ipa_chkp_produce_thunks (gcc::context
*ctxt
)
856 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks
, ctxt
)
859 /* opt_pass methods: */
860 virtual opt_pass
* clone ()
862 return new pass_ipa_chkp_produce_thunks (m_ctxt
);
865 virtual bool gate (function
*)
867 return flag_check_pointer_bounds
;
870 virtual unsigned int execute (function
*)
872 return chkp_produce_thunks (false);
875 }; // class pass_chkp_produce_thunks
877 simple_ipa_opt_pass
*
878 make_pass_ipa_chkp_versioning (gcc::context
*ctxt
)
880 return new pass_ipa_chkp_versioning (ctxt
);
883 simple_ipa_opt_pass
*
884 make_pass_ipa_chkp_early_produce_thunks (gcc::context
*ctxt
)
886 return new pass_ipa_chkp_early_produce_thunks (ctxt
);
889 simple_ipa_opt_pass
*
890 make_pass_ipa_chkp_produce_thunks (gcc::context
*ctxt
)
892 return new pass_ipa_chkp_produce_thunks (ctxt
);