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"
32 #include "fold-const.h"
33 #include "stor-layout.h"
34 #include "tree-pass.h"
35 #include "stringpool.h"
37 #include "gimple-expr.h"
39 #include "hard-reg-set.h"
42 #include "tree-ssa-alias.h"
44 #include "basic-block.h"
47 #include "lto-streamer.h"
49 #include "tree-chkp.h"
50 #include "tree-inline.h"
53 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
55 In instrumented code each pointer is provided with bounds. For input
56 pointer parameters it means we also have bounds passed. For calls it
57 means we have additional bounds arguments for pointer arguments.
59 To have all IPA optimizations working correctly we have to express
60 dataflow between passed and received bounds explicitly via additional
61 entries in function declaration arguments list and in function type.
62 Since we may have both instrumented and not instrumented code at the
63 same time, we cannot replace all original functions with their
64 instrumented variants. Therefore we create clones (versions) instead.
66 Instrumentation clones creation is a separate IPA pass which is a part
67 of early local passes. Clones are created after SSA is built (because
68 instrumentation pass works on SSA) and before any transformations
69 which may change pointer flow and therefore lead to incorrect code
70 instrumentation (possibly causing false bounds check failures).
72 Instrumentation clones have pointer bounds arguments added right after
73 pointer arguments. Clones have assembler name of the original
74 function with suffix added. New assembler name is in transparent
75 alias chain with the original name. Thus we expect all calls to the
76 original and instrumented functions look similar in assembler.
78 During instrumentation versioning pass we create instrumented versions
79 of all function with body and also for all their aliases and thunks.
80 Clones for functions with no body are created on demand (usually
81 during call instrumentation).
83 Original and instrumented function nodes are connected with IPA
84 reference IPA_REF_CHKP. It is mostly done to have reachability
85 analysis working correctly. We may have no references to the
86 instrumented function in the code but it still should be counted
87 as reachable if the original function is reachable.
89 When original function bodies are not needed anymore we release
90 them and transform functions into a special kind of thunks. Each
91 thunk has a call edge to the instrumented version. These thunks
92 help to keep externally visible instrumented functions visible
93 when linker resolution files are used. Linker has no info about
94 connection between original and instrumented function and
95 therefore we may wrongly decide (due to difference in assembler
96 names) that instrumented function version is local and can be
99 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
100 #define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
102 /* Return 1 calls to FNDECL should be replaced with
103 a call to wrapper function. */
105 chkp_wrap_function (tree fndecl
)
107 if (!flag_chkp_use_wrappers
)
110 if (DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
)
112 switch (DECL_FUNCTION_CODE (fndecl
))
114 case BUILT_IN_STRLEN
:
115 case BUILT_IN_STRCPY
:
116 case BUILT_IN_STRNCPY
:
117 case BUILT_IN_STPCPY
:
118 case BUILT_IN_STPNCPY
:
119 case BUILT_IN_STRCAT
:
120 case BUILT_IN_STRNCAT
:
121 case BUILT_IN_MEMCPY
:
122 case BUILT_IN_MEMPCPY
:
123 case BUILT_IN_MEMSET
:
124 case BUILT_IN_MEMMOVE
:
126 case BUILT_IN_MALLOC
:
127 case BUILT_IN_CALLOC
:
128 case BUILT_IN_REALLOC
:
140 chkp_wrap_function_name (tree fndecl
)
142 gcc_assert (DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
);
144 switch (DECL_FUNCTION_CODE (fndecl
))
146 case BUILT_IN_STRLEN
:
147 return CHKP_WRAPPER_SYMBOL_PREFIX
"strlen";
148 case BUILT_IN_STRCPY
:
149 return CHKP_WRAPPER_SYMBOL_PREFIX
"strcpy";
150 case BUILT_IN_STRNCPY
:
151 return CHKP_WRAPPER_SYMBOL_PREFIX
"strncpy";
152 case BUILT_IN_STPCPY
:
153 return CHKP_WRAPPER_SYMBOL_PREFIX
"stpcpy";
154 case BUILT_IN_STPNCPY
:
155 return CHKP_WRAPPER_SYMBOL_PREFIX
"stpncpy";
156 case BUILT_IN_STRCAT
:
157 return CHKP_WRAPPER_SYMBOL_PREFIX
"strcat";
158 case BUILT_IN_STRNCAT
:
159 return CHKP_WRAPPER_SYMBOL_PREFIX
"strncat";
160 case BUILT_IN_MEMCPY
:
161 return CHKP_WRAPPER_SYMBOL_PREFIX
"memcpy";
162 case BUILT_IN_MEMPCPY
:
163 return CHKP_WRAPPER_SYMBOL_PREFIX
"mempcpy";
164 case BUILT_IN_MEMSET
:
165 return CHKP_WRAPPER_SYMBOL_PREFIX
"memset";
166 case BUILT_IN_MEMMOVE
:
167 return CHKP_WRAPPER_SYMBOL_PREFIX
"memmove";
169 return CHKP_WRAPPER_SYMBOL_PREFIX
"bzero";
170 case BUILT_IN_MALLOC
:
171 return CHKP_WRAPPER_SYMBOL_PREFIX
"malloc";
172 case BUILT_IN_CALLOC
:
173 return CHKP_WRAPPER_SYMBOL_PREFIX
"calloc";
174 case BUILT_IN_REALLOC
:
175 return CHKP_WRAPPER_SYMBOL_PREFIX
"realloc";
184 /* Build a clone of FNDECL with a modified name. */
187 chkp_build_instrumented_fndecl (tree fndecl
)
189 tree new_decl
= copy_node (fndecl
);
193 /* called_as_built_in checks DECL_NAME to identify calls to
194 builtins. We want instrumented calls to builtins to be
195 recognized by called_as_built_in. Therefore use original
196 DECL_NAME for cloning with no prefixes. */
197 s
= IDENTIFIER_POINTER (DECL_NAME (fndecl
));
199 DECL_NAME (new_decl
) = get_identifier (s
.c_str ());
201 /* References to the original and to the instrumented version
202 should look the same in the output assembly. And we cannot
203 use the same assembler name for the instrumented version
204 because it conflicts with decl merging algorithms in LTO.
205 Achieve the result by using transparent alias name for the
206 instrumented version. */
207 if (chkp_wrap_function(fndecl
))
209 new_name
= get_identifier (chkp_wrap_function_name (fndecl
));
210 DECL_VISIBILITY (new_decl
) = VISIBILITY_DEFAULT
;
214 s
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl
));
216 new_name
= get_identifier (s
.c_str ());
217 IDENTIFIER_TRANSPARENT_ALIAS (new_name
) = 1;
218 TREE_CHAIN (new_name
) = DECL_ASSEMBLER_NAME (fndecl
);
220 SET_DECL_ASSEMBLER_NAME (new_decl
, new_name
);
222 /* For functions with body versioning will make a copy of arguments.
223 For functions with no body we need to do it here. */
224 if (!gimple_has_body_p (fndecl
))
225 DECL_ARGUMENTS (new_decl
) = copy_list (DECL_ARGUMENTS (fndecl
));
227 /* We are going to modify attributes list and therefore should
229 DECL_ATTRIBUTES (new_decl
) = copy_list (DECL_ATTRIBUTES (fndecl
));
231 /* Change builtin function code. */
232 if (DECL_BUILT_IN (new_decl
))
234 gcc_assert (DECL_BUILT_IN_CLASS (new_decl
) == BUILT_IN_NORMAL
);
235 gcc_assert (DECL_FUNCTION_CODE (new_decl
) < BEGIN_CHKP_BUILTINS
);
236 DECL_FUNCTION_CODE (new_decl
)
237 = (enum built_in_function
)(DECL_FUNCTION_CODE (new_decl
)
238 + BEGIN_CHKP_BUILTINS
+ 1);
245 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
246 Integer operands are replaced with values according to
247 INDEXES map having LEN elements. For operands out of len
248 we just add DELTA. */
251 chkp_map_attr_arg_indexes (tree attrs
, const char *attr_name
,
252 unsigned *indexes
, int len
, int delta
)
254 tree attr
= lookup_attribute (attr_name
, attrs
);
260 TREE_VALUE (attr
) = copy_list (TREE_VALUE (attr
));
261 for (op
= TREE_VALUE (attr
); op
; op
= TREE_CHAIN (op
))
265 if (TREE_CODE (TREE_VALUE (op
)) != INTEGER_CST
)
268 idx
= TREE_INT_CST_LOW (TREE_VALUE (op
));
270 /* If idx exceeds indexes length then we just
271 keep it at the same distance from the last
276 idx
= indexes
[idx
- 1] + 1;
277 TREE_VALUE (op
) = build_int_cst (TREE_TYPE (TREE_VALUE (op
)), idx
);
281 /* Make a copy of function type ORIG_TYPE adding pointer
282 bounds as additional arguments. */
285 chkp_copy_function_type_adding_bounds (tree orig_type
)
288 tree arg_type
, attrs
;
289 unsigned len
= list_length (TYPE_ARG_TYPES (orig_type
));
290 unsigned *indexes
= XALLOCAVEC (unsigned, len
);
291 unsigned idx
= 0, new_idx
= 0;
293 for (arg_type
= TYPE_ARG_TYPES (orig_type
);
295 arg_type
= TREE_CHAIN (arg_type
))
296 if (TREE_VALUE (arg_type
) == void_type_node
)
298 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type
))
299 || pass_by_reference (NULL
, TYPE_MODE (TREE_VALUE (arg_type
)),
300 TREE_VALUE (arg_type
), true)
301 || chkp_type_has_pointer (TREE_VALUE (arg_type
)))
304 /* We may use original type if there are no bounds passed. */
308 type
= build_distinct_type_copy (orig_type
);
309 TYPE_ARG_TYPES (type
) = copy_list (TYPE_ARG_TYPES (type
));
311 for (arg_type
= TYPE_ARG_TYPES (type
);
313 arg_type
= TREE_CHAIN (arg_type
))
315 indexes
[idx
++] = new_idx
++;
317 /* pass_by_reference returns 1 for void type,
318 so check for it first. */
319 if (TREE_VALUE (arg_type
) == void_type_node
)
321 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type
))
322 || pass_by_reference (NULL
, TYPE_MODE (TREE_VALUE (arg_type
)),
323 TREE_VALUE (arg_type
), true))
325 tree new_type
= build_tree_list (NULL_TREE
,
326 pointer_bounds_type_node
);
327 TREE_CHAIN (new_type
) = TREE_CHAIN (arg_type
);
328 TREE_CHAIN (arg_type
) = new_type
;
330 arg_type
= TREE_CHAIN (arg_type
);
333 else if (chkp_type_has_pointer (TREE_VALUE (arg_type
)))
335 bitmap slots
= BITMAP_ALLOC (NULL
);
339 chkp_find_bound_slots (TREE_VALUE (arg_type
), slots
);
341 EXECUTE_IF_SET_IN_BITMAP (slots
, 0, bnd_no
, bi
)
343 tree new_type
= build_tree_list (NULL_TREE
,
344 pointer_bounds_type_node
);
345 TREE_CHAIN (new_type
) = TREE_CHAIN (arg_type
);
346 TREE_CHAIN (arg_type
) = new_type
;
348 arg_type
= TREE_CHAIN (arg_type
);
355 /* If function type has attribute with arg indexes then
356 we have to copy it fixing attribute ops. Map for
357 fixing is in indexes array. */
358 attrs
= TYPE_ATTRIBUTES (type
);
359 if (lookup_attribute ("nonnull", attrs
)
360 || lookup_attribute ("format", attrs
)
361 || lookup_attribute ("format_arg", attrs
))
363 int delta
= new_idx
- len
;
364 attrs
= copy_list (TYPE_ATTRIBUTES (type
));
365 chkp_map_attr_arg_indexes (attrs
, "nonnull", indexes
, len
, delta
);
366 chkp_map_attr_arg_indexes (attrs
, "format", indexes
, len
, delta
);
367 chkp_map_attr_arg_indexes (attrs
, "format_arg", indexes
, len
, delta
);
368 TYPE_ATTRIBUTES (type
) = attrs
;
374 /* For given function FNDECL add bounds arguments to arguments
378 chkp_add_bounds_params_to_function (tree fndecl
)
382 for (arg
= DECL_ARGUMENTS (fndecl
); arg
; arg
= DECL_CHAIN (arg
))
385 std::string new_name
= CHKP_BOUNDS_OF_SYMBOL_PREFIX
;
389 new_name
+= IDENTIFIER_POINTER (DECL_NAME (arg
));
393 snprintf (uid
, 25, "D.%u", DECL_UID (arg
));
397 new_arg
= build_decl (DECL_SOURCE_LOCATION (arg
), PARM_DECL
,
398 get_identifier (new_name
.c_str ()),
399 pointer_bounds_type_node
);
400 DECL_ARG_TYPE (new_arg
) = pointer_bounds_type_node
;
401 DECL_CONTEXT (new_arg
) = DECL_CONTEXT (arg
);
402 DECL_ARTIFICIAL (new_arg
) = 1;
403 DECL_CHAIN (new_arg
) = DECL_CHAIN (arg
);
404 DECL_CHAIN (arg
) = new_arg
;
406 arg
= DECL_CHAIN (arg
);
409 else if (chkp_type_has_pointer (TREE_TYPE (arg
)))
412 bitmap slots
= BITMAP_ALLOC (NULL
);
416 chkp_find_bound_slots (TREE_TYPE (arg
), slots
);
418 EXECUTE_IF_SET_IN_BITMAP (slots
, 0, bnd_no
, bi
)
420 std::string new_name
= CHKP_BOUNDS_OF_SYMBOL_PREFIX
;
424 if (DECL_NAME (orig_arg
))
425 new_name
+= IDENTIFIER_POINTER (DECL_NAME (orig_arg
));
428 snprintf (offs
, 25, "D.%u", DECL_UID (arg
));
431 snprintf (offs
, 25, "__%u", bnd_no
* POINTER_SIZE
/ BITS_PER_UNIT
);
433 new_arg
= build_decl (DECL_SOURCE_LOCATION (orig_arg
),
435 get_identifier (new_name
.c_str ()),
436 pointer_bounds_type_node
);
437 DECL_ARG_TYPE (new_arg
) = pointer_bounds_type_node
;
438 DECL_CONTEXT (new_arg
) = DECL_CONTEXT (orig_arg
);
439 DECL_ARTIFICIAL (new_arg
) = 1;
440 DECL_CHAIN (new_arg
) = DECL_CHAIN (arg
);
441 DECL_CHAIN (arg
) = new_arg
;
443 arg
= DECL_CHAIN (arg
);
449 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl
));
452 /* Return an instrumentation clone for builtin function
453 FNDECL. Create one if needed. */
456 chkp_maybe_clone_builtin_fndecl (tree fndecl
)
459 enum built_in_function fcode
= DECL_FUNCTION_CODE (fndecl
);
461 gcc_assert (DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
462 && fcode
< BEGIN_CHKP_BUILTINS
);
464 fcode
= (enum built_in_function
) (fcode
+ BEGIN_CHKP_BUILTINS
+ 1);
465 clone
= builtin_decl_explicit (fcode
);
469 clone
= chkp_build_instrumented_fndecl (fndecl
);
470 chkp_add_bounds_params_to_function (clone
);
472 gcc_assert (DECL_FUNCTION_CODE (clone
) == fcode
);
474 set_builtin_decl (fcode
, clone
, false);
479 /* Return 1 if function FNDECL should be instrumented. */
482 chkp_instrumentable_p (tree fndecl
)
484 struct function
*fn
= DECL_STRUCT_FUNCTION (fndecl
);
485 return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl
))
486 && (!flag_chkp_instrument_marked_only
487 || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl
)))
488 && (!fn
|| !copy_forbidden (fn
, fndecl
)));
491 /* Return clone created for instrumentation of NODE or NULL. */
494 chkp_maybe_create_clone (tree fndecl
)
496 cgraph_node
*node
= cgraph_node::get_create (fndecl
);
497 cgraph_node
*clone
= node
->instrumented_version
;
499 gcc_assert (!node
->instrumentation_clone
);
501 if (DECL_BUILT_IN (fndecl
)
502 && (DECL_BUILT_IN_CLASS (fndecl
) != BUILT_IN_NORMAL
503 || DECL_FUNCTION_CODE (fndecl
) >= BEGIN_CHKP_BUILTINS
))
506 clone
= node
->instrumented_version
;
508 /* Some instrumented builtin function calls may be optimized and
509 cgraph nodes may be removed as unreachable. Later optimizations
510 may generate new calls to removed functions and in this case
511 we have to recreate cgraph node. FUNCTION_DECL for instrumented
512 builtin still exists and should be reused in such case. */
513 if (DECL_BUILT_IN_CLASS (fndecl
) == BUILT_IN_NORMAL
514 && fndecl
== builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl
))
517 enum built_in_function fncode
= DECL_FUNCTION_CODE (fndecl
);
520 fncode
= (enum built_in_function
) (fncode
+ BEGIN_CHKP_BUILTINS
+ 1);
521 new_decl
= builtin_decl_explicit (fncode
);
523 /* We've actually already created an instrumented clone once.
527 clone
= cgraph_node::get (new_decl
);
531 gcc_assert (!gimple_has_body_p (fndecl
));
532 clone
= cgraph_node::get_create (new_decl
);
533 clone
->externally_visible
= node
->externally_visible
;
534 clone
->local
= node
->local
;
535 clone
->address_taken
= node
->address_taken
;
536 clone
->thunk
= node
->thunk
;
537 clone
->alias
= node
->alias
;
538 clone
->weakref
= node
->weakref
;
539 clone
->cpp_implicit_alias
= node
->cpp_implicit_alias
;
540 clone
->orig_decl
= fndecl
;
541 clone
->instrumentation_clone
= true;
544 clone
->instrumented_version
= node
;
545 node
->instrumented_version
= clone
;
551 tree new_decl
= chkp_build_instrumented_fndecl (fndecl
);
552 struct cgraph_edge
*e
;
556 clone
= node
->create_version_clone (new_decl
, vNULL
, NULL
);
557 clone
->externally_visible
= node
->externally_visible
;
558 clone
->local
= node
->local
;
559 clone
->address_taken
= node
->address_taken
;
560 clone
->thunk
= node
->thunk
;
561 clone
->alias
= node
->alias
;
562 clone
->weakref
= node
->weakref
;
563 clone
->cpp_implicit_alias
= node
->cpp_implicit_alias
;
564 clone
->instrumented_version
= node
;
565 clone
->orig_decl
= fndecl
;
566 clone
->instrumentation_clone
= true;
567 node
->instrumented_version
= clone
;
569 if (gimple_has_body_p (fndecl
))
571 /* If function will not be instrumented, then it's instrumented
572 version is a thunk for the original. */
573 if (!chkp_instrumentable_p (fndecl
))
575 clone
->remove_callees ();
576 clone
->remove_all_references ();
577 clone
->thunk
.thunk_p
= true;
578 clone
->thunk
.add_pointer_bounds_args
= true;
579 clone
->create_edge (node
, NULL
, 0, CGRAPH_FREQ_BASE
);
580 /* Thunk shouldn't be a cdtor. */
581 DECL_STATIC_CONSTRUCTOR (clone
->decl
) = 0;
582 DECL_STATIC_DESTRUCTOR (clone
->decl
) = 0;
586 tree_function_versioning (fndecl
, new_decl
, NULL
, false,
587 NULL
, false, NULL
, NULL
);
588 clone
->lowered
= true;
592 /* New params are inserted after versioning because it
593 actually copies args list from the original decl. */
594 chkp_add_bounds_params_to_function (new_decl
);
596 /* Remember builtin fndecl. */
597 if (DECL_BUILT_IN_CLASS (clone
->decl
) == BUILT_IN_NORMAL
598 && fndecl
== builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl
)))
600 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone
->decl
)));
601 set_builtin_decl (DECL_FUNCTION_CODE (clone
->decl
),
605 /* Clones have the same comdat group as originals. */
606 if (node
->same_comdat_group
607 || (DECL_ONE_ONLY (node
->decl
)
608 && !DECL_EXTERNAL (node
->decl
)))
609 clone
->add_to_same_comdat_group (node
);
611 if (gimple_has_body_p (fndecl
))
612 symtab
->call_cgraph_insertion_hooks (clone
);
614 /* Clone all aliases. */
615 for (i
= 0; node
->iterate_direct_aliases (i
, ref
); i
++)
616 chkp_maybe_create_clone (ref
->referring
->decl
);
618 /* Clone all thunks. */
619 for (e
= node
->callers
; e
; e
= e
->next_caller
)
620 if (e
->caller
->thunk
.thunk_p
621 && !e
->caller
->thunk
.add_pointer_bounds_args
622 && !e
->caller
->instrumentation_clone
)
624 struct cgraph_node
*thunk
625 = chkp_maybe_create_clone (e
->caller
->decl
);
626 /* Redirect thunk clone edge to the node clone. */
627 thunk
->callees
->redirect_callee (clone
);
630 /* For aliases and thunks we should make sure target is cloned
631 to have proper references and edges. */
632 if (node
->thunk
.thunk_p
)
633 chkp_maybe_create_clone (node
->callees
->callee
->decl
);
634 else if (node
->alias
)
636 struct cgraph_node
*target
;
638 ref
= node
->ref_list
.first_reference ();
641 target
= chkp_maybe_create_clone (ref
->referred
->decl
);
642 clone
->create_reference (target
, IPA_REF_ALIAS
);
645 if (node
->alias_target
)
647 if (TREE_CODE (node
->alias_target
) == FUNCTION_DECL
)
649 target
= chkp_maybe_create_clone (node
->alias_target
);
650 clone
->alias_target
= target
->decl
;
653 clone
->alias_target
= node
->alias_target
;
657 /* Add IPA reference. It's main role is to keep instrumented
658 version reachable while original node is reachable. */
659 ref
= node
->create_reference (clone
, IPA_REF_CHKP
, NULL
);
665 /* Create clone for all functions to be instrumented. */
668 chkp_versioning (void)
670 struct cgraph_node
*node
;
673 bitmap_obstack_initialize (NULL
);
675 FOR_EACH_DEFINED_FUNCTION (node
)
677 if (!node
->instrumentation_clone
678 && !node
->instrumented_version
680 && !node
->thunk
.thunk_p
681 && (!DECL_BUILT_IN (node
->decl
)
682 || (DECL_BUILT_IN_CLASS (node
->decl
) == BUILT_IN_NORMAL
683 && DECL_FUNCTION_CODE (node
->decl
) < BEGIN_CHKP_BUILTINS
)))
685 if (chkp_instrumentable_p (node
->decl
))
686 chkp_maybe_create_clone (node
->decl
);
687 else if ((reason
= copy_forbidden (DECL_STRUCT_FUNCTION (node
->decl
),
690 if (warning_at (DECL_SOURCE_LOCATION (node
->decl
), OPT_Wchkp
,
691 "function cannot be instrumented"))
692 inform (DECL_SOURCE_LOCATION (node
->decl
), reason
, node
->decl
);
697 /* Mark all aliases and thunks of functions with no instrumented
698 version as legacy function. */
699 FOR_EACH_DEFINED_FUNCTION (node
)
701 if (!node
->instrumentation_clone
702 && !node
->instrumented_version
703 && (node
->alias
|| node
->thunk
.thunk_p
)
704 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node
->decl
)))
705 DECL_ATTRIBUTES (node
->decl
)
706 = tree_cons (get_identifier ("bnd_legacy"), NULL
,
707 DECL_ATTRIBUTES (node
->decl
));
710 bitmap_obstack_release (NULL
);
715 /* In this pass we remove bodies of functions having
716 instrumented version. Functions with removed bodies
717 become a special kind of thunks to provide a connection
718 between calls to the original version and instrumented
722 chkp_produce_thunks (bool early
)
724 struct cgraph_node
*node
;
726 FOR_EACH_DEFINED_FUNCTION (node
)
728 if (!node
->instrumentation_clone
729 && node
->instrumented_version
730 && gimple_has_body_p (node
->decl
)
731 && gimple_has_body_p (node
->instrumented_version
->decl
)
732 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node
->decl
))
735 node
->release_body ();
736 node
->remove_callees ();
737 node
->remove_all_references ();
739 node
->thunk
.thunk_p
= true;
740 node
->thunk
.add_pointer_bounds_args
= true;
741 node
->create_edge (node
->instrumented_version
, NULL
,
742 0, CGRAPH_FREQ_BASE
);
743 node
->create_reference (node
->instrumented_version
,
745 /* Thunk shouldn't be a cdtor. */
746 DECL_STATIC_CONSTRUCTOR (node
->decl
) = 0;
747 DECL_STATIC_DESTRUCTOR (node
->decl
) = 0;
751 /* Mark instrumentation clones created for aliases and thunks
752 as insttrumented so they could be removed as unreachable
756 FOR_EACH_DEFINED_FUNCTION (node
)
758 if (node
->instrumentation_clone
759 && (node
->alias
|| node
->thunk
.thunk_p
)
760 && !chkp_function_instrumented_p (node
->decl
))
761 chkp_function_mark_instrumented (node
->decl
);
765 return TODO_remove_functions
;
768 const pass_data pass_data_ipa_chkp_versioning
=
770 SIMPLE_IPA_PASS
, /* type */
771 "chkp_versioning", /* name */
772 OPTGROUP_NONE
, /* optinfo_flags */
774 0, /* properties_required */
775 0, /* properties_provided */
776 0, /* properties_destroyed */
777 0, /* todo_flags_start */
778 0 /* todo_flags_finish */
781 const pass_data pass_data_ipa_chkp_early_produce_thunks
=
783 SIMPLE_IPA_PASS
, /* type */
784 "chkp_ecleanup", /* name */
785 OPTGROUP_NONE
, /* optinfo_flags */
787 0, /* properties_required */
788 0, /* properties_provided */
789 0, /* properties_destroyed */
790 0, /* todo_flags_start */
791 0 /* todo_flags_finish */
794 const pass_data pass_data_ipa_chkp_produce_thunks
=
796 SIMPLE_IPA_PASS
, /* type */
797 "chkp_cleanup", /* name */
798 OPTGROUP_NONE
, /* optinfo_flags */
800 0, /* properties_required */
801 0, /* properties_provided */
802 0, /* properties_destroyed */
803 0, /* todo_flags_start */
804 0 /* todo_flags_finish */
807 class pass_ipa_chkp_versioning
: public simple_ipa_opt_pass
810 pass_ipa_chkp_versioning (gcc::context
*ctxt
)
811 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning
, ctxt
)
814 /* opt_pass methods: */
815 virtual opt_pass
* clone ()
817 return new pass_ipa_chkp_versioning (m_ctxt
);
820 virtual bool gate (function
*)
822 return flag_check_pointer_bounds
;
825 virtual unsigned int execute (function
*)
827 return chkp_versioning ();
830 }; // class pass_ipa_chkp_versioning
832 class pass_ipa_chkp_early_produce_thunks
: public simple_ipa_opt_pass
835 pass_ipa_chkp_early_produce_thunks (gcc::context
*ctxt
)
836 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks
, ctxt
)
839 /* opt_pass methods: */
840 virtual opt_pass
* clone ()
842 return new pass_ipa_chkp_early_produce_thunks (m_ctxt
);
845 virtual bool gate (function
*)
847 return flag_check_pointer_bounds
;
850 virtual unsigned int execute (function
*)
852 return chkp_produce_thunks (true);
855 }; // class pass_chkp_produce_thunks
857 class pass_ipa_chkp_produce_thunks
: public simple_ipa_opt_pass
860 pass_ipa_chkp_produce_thunks (gcc::context
*ctxt
)
861 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks
, ctxt
)
864 /* opt_pass methods: */
865 virtual opt_pass
* clone ()
867 return new pass_ipa_chkp_produce_thunks (m_ctxt
);
870 virtual bool gate (function
*)
872 return flag_check_pointer_bounds
;
875 virtual unsigned int execute (function
*)
877 return chkp_produce_thunks (false);
880 }; // class pass_chkp_produce_thunks
882 simple_ipa_opt_pass
*
883 make_pass_ipa_chkp_versioning (gcc::context
*ctxt
)
885 return new pass_ipa_chkp_versioning (ctxt
);
888 simple_ipa_opt_pass
*
889 make_pass_ipa_chkp_early_produce_thunks (gcc::context
*ctxt
)
891 return new pass_ipa_chkp_early_produce_thunks (ctxt
);
894 simple_ipa_opt_pass
*
895 make_pass_ipa_chkp_produce_thunks (gcc::context
*ctxt
)
897 return new pass_ipa_chkp_produce_thunks (ctxt
);