function.h (struct incoming_args): Move struct.
[gcc.git] / gcc / ipa-chkp.c
1 /* Pointer Bounds Checker IPA passes.
2 Copyright (C) 2014-2015 Free Software Foundation, Inc.
3 Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
4
5 This file is part of GCC.
6
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.
11
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.
16
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/>. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "alias.h"
25 #include "symtab.h"
26 #include "options.h"
27 #include "tree.h"
28 #include "fold-const.h"
29 #include "stor-layout.h"
30 #include "tree-pass.h"
31 #include "stringpool.h"
32 #include "bitmap.h"
33 #include "gimple-expr.h"
34 #include "tm.h"
35 #include "hard-reg-set.h"
36 #include "function.h"
37 #include "calls.h"
38 #include "tree-ssa-alias.h"
39 #include "predict.h"
40 #include "basic-block.h"
41 #include "gimple.h"
42 #include "ipa-ref.h"
43 #include "lto-streamer.h"
44 #include "cgraph.h"
45 #include "tree-chkp.h"
46 #include "tree-inline.h"
47 #include "ipa-chkp.h"
48
49 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
50
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.
54
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.
61
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).
67
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.
73
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).
78
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.
84
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
93 removed. */
94
95 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
96 #define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
97
98 /* Return 1 calls to FNDECL should be replaced with
99 a call to wrapper function. */
100 bool
101 chkp_wrap_function (tree fndecl)
102 {
103 if (!flag_chkp_use_wrappers)
104 return false;
105
106 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
107 {
108 switch (DECL_FUNCTION_CODE (fndecl))
109 {
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:
121 case BUILT_IN_BZERO:
122 case BUILT_IN_MALLOC:
123 case BUILT_IN_CALLOC:
124 case BUILT_IN_REALLOC:
125 return 1;
126
127 default:
128 return 0;
129 }
130 }
131
132 return false;
133 }
134
135 static const char *
136 chkp_wrap_function_name (tree fndecl)
137 {
138 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL);
139
140 switch (DECL_FUNCTION_CODE (fndecl))
141 {
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";
164 case BUILT_IN_BZERO:
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";
172
173 default:
174 gcc_unreachable ();
175 }
176
177 return "";
178 }
179
180 /* Build a clone of FNDECL with a modified name. */
181
182 static tree
183 chkp_build_instrumented_fndecl (tree fndecl)
184 {
185 tree new_decl = copy_node (fndecl);
186 tree new_name;
187 std::string s;
188
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));
194 s += ".chkp";
195 DECL_NAME (new_decl) = get_identifier (s.c_str ());
196
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))
204 {
205 new_name = get_identifier (chkp_wrap_function_name (fndecl));
206 DECL_VISIBILITY (new_decl) = VISIBILITY_DEFAULT;
207 }
208 else
209 {
210 s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
211 s += ".chkp";
212 new_name = get_identifier (s.c_str ());
213 IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
214 TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
215 }
216 SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
217
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));
222
223 /* We are going to modify attributes list and therefore should
224 make own copy. */
225 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
226
227 /* Change builtin function code. */
228 if (DECL_BUILT_IN (new_decl))
229 {
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);
235 }
236
237 return new_decl;
238 }
239
240
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. */
245
246 static void
247 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
248 unsigned *indexes, int len, int delta)
249 {
250 tree attr = lookup_attribute (attr_name, attrs);
251 tree op;
252
253 if (!attr)
254 return;
255
256 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
257 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
258 {
259 int idx;
260
261 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
262 continue;
263
264 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
265
266 /* If idx exceeds indexes length then we just
267 keep it at the same distance from the last
268 known arg. */
269 if (idx > len)
270 idx += delta;
271 else
272 idx = indexes[idx - 1] + 1;
273 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
274 }
275 }
276
277 /* Make a copy of function type ORIG_TYPE adding pointer
278 bounds as additional arguments. */
279
280 tree
281 chkp_copy_function_type_adding_bounds (tree orig_type)
282 {
283 tree 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;
288
289 for (arg_type = TYPE_ARG_TYPES (orig_type);
290 arg_type;
291 arg_type = TREE_CHAIN (arg_type))
292 if (TREE_VALUE (arg_type) == void_type_node)
293 continue;
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)))
298 break;
299
300 /* We may use original type if there are no bounds passed. */
301 if (!arg_type)
302 return orig_type;
303
304 type = build_distinct_type_copy (orig_type);
305 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
306
307 for (arg_type = TYPE_ARG_TYPES (type);
308 arg_type;
309 arg_type = TREE_CHAIN (arg_type))
310 {
311 indexes[idx++] = new_idx++;
312
313 /* pass_by_reference returns 1 for void type,
314 so check for it first. */
315 if (TREE_VALUE (arg_type) == void_type_node)
316 continue;
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))
320 {
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;
325
326 arg_type = TREE_CHAIN (arg_type);
327 new_idx++;
328 }
329 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
330 {
331 bitmap slots = BITMAP_ALLOC (NULL);
332 bitmap_iterator bi;
333 unsigned bnd_no;
334
335 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
336
337 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
338 {
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;
343
344 arg_type = TREE_CHAIN (arg_type);
345 new_idx++;
346 }
347 BITMAP_FREE (slots);
348 }
349 }
350
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))
358 {
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;
365 }
366
367 return type;
368 }
369
370 /* For given function FNDECL add bounds arguments to arguments
371 list. */
372
373 static void
374 chkp_add_bounds_params_to_function (tree fndecl)
375 {
376 tree arg;
377
378 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
379 if (BOUNDED_P (arg))
380 {
381 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
382 tree new_arg;
383
384 if (DECL_NAME (arg))
385 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
386 else
387 {
388 char uid[25];
389 snprintf (uid, 25, "D.%u", DECL_UID (arg));
390 new_name += uid;
391 }
392
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;
401
402 arg = DECL_CHAIN (arg);
403
404 }
405 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
406 {
407 tree orig_arg = arg;
408 bitmap slots = BITMAP_ALLOC (NULL);
409 bitmap_iterator bi;
410 unsigned bnd_no;
411
412 chkp_find_bound_slots (TREE_TYPE (arg), slots);
413
414 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
415 {
416 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
417 tree new_arg;
418 char offs[25];
419
420 if (DECL_NAME (orig_arg))
421 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
422 else
423 {
424 snprintf (offs, 25, "D.%u", DECL_UID (arg));
425 new_name += offs;
426 }
427 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
428
429 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
430 PARM_DECL,
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;
438
439 arg = DECL_CHAIN (arg);
440 }
441 BITMAP_FREE (slots);
442 }
443
444 TREE_TYPE (fndecl) =
445 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
446 }
447
448 /* Return an instrumentation clone for builtin function
449 FNDECL. Create one if needed. */
450
451 tree
452 chkp_maybe_clone_builtin_fndecl (tree fndecl)
453 {
454 tree clone;
455 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
456
457 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
458 && fcode < BEGIN_CHKP_BUILTINS);
459
460 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
461 clone = builtin_decl_explicit (fcode);
462 if (clone)
463 return clone;
464
465 clone = chkp_build_instrumented_fndecl (fndecl);
466 chkp_add_bounds_params_to_function (clone);
467
468 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
469
470 set_builtin_decl (fcode, clone, false);
471
472 return clone;
473 }
474
475 /* Return 1 if function FNDECL should be instrumented. */
476
477 bool
478 chkp_instrumentable_p (tree fndecl)
479 {
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)));
485 }
486
487 /* Return clone created for instrumentation of NODE or NULL. */
488
489 cgraph_node *
490 chkp_maybe_create_clone (tree fndecl)
491 {
492 cgraph_node *node = cgraph_node::get_create (fndecl);
493 cgraph_node *clone = node->instrumented_version;
494
495 gcc_assert (!node->instrumentation_clone);
496
497 if (DECL_BUILT_IN (fndecl)
498 && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
499 || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
500 return NULL;
501
502 clone = node->instrumented_version;
503
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))
511 && !clone)
512 {
513 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
514 tree new_decl;
515
516 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
517 new_decl = builtin_decl_explicit (fncode);
518
519 /* We've actually already created an instrumented clone once.
520 Restore it. */
521 if (new_decl)
522 {
523 clone = cgraph_node::get (new_decl);
524
525 if (!clone)
526 {
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;
538 }
539
540 clone->instrumented_version = node;
541 node->instrumented_version = clone;
542 }
543 }
544
545 if (!clone)
546 {
547 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
548 struct cgraph_edge *e;
549 struct ipa_ref *ref;
550 int i;
551
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;
564
565 if (gimple_has_body_p (fndecl))
566 {
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;
571 }
572
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);
576
577 /* Remember builtin fndecl. */
578 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
579 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
580 {
581 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
582 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
583 clone->decl, false);
584 }
585
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);
591
592 if (gimple_has_body_p (fndecl))
593 symtab->call_cgraph_insertion_hooks (clone);
594
595 /* Clone all aliases. */
596 for (i = 0; node->iterate_direct_aliases (i, ref); i++)
597 chkp_maybe_create_clone (ref->referring->decl);
598
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)
604 {
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);
609 }
610
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)
616 {
617 struct cgraph_node *target;
618
619 ref = node->ref_list.first_reference ();
620 if (ref)
621 {
622 target = chkp_maybe_create_clone (ref->referred->decl);
623 clone->create_reference (target, IPA_REF_ALIAS);
624 }
625
626 if (node->alias_target)
627 {
628 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
629 {
630 target = chkp_maybe_create_clone (node->alias_target);
631 clone->alias_target = target->decl;
632 }
633 else
634 clone->alias_target = node->alias_target;
635 }
636 }
637
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);
641 }
642
643 return clone;
644 }
645
646 /* Create clone for all functions to be instrumented. */
647
648 static unsigned int
649 chkp_versioning (void)
650 {
651 struct cgraph_node *node;
652 const char *reason;
653
654 bitmap_obstack_initialize (NULL);
655
656 FOR_EACH_DEFINED_FUNCTION (node)
657 {
658 if (!node->instrumentation_clone
659 && !node->instrumented_version
660 && !node->alias
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)))
665 {
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),
669 node->decl)))
670 {
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);
674 }
675 }
676 }
677
678 /* Mark all aliases and thunks of functions with no instrumented
679 version as legacy function. */
680 FOR_EACH_DEFINED_FUNCTION (node)
681 {
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));
689 }
690
691 bitmap_obstack_release (NULL);
692
693 return 0;
694 }
695
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
700 function. */
701
702 static unsigned int
703 chkp_produce_thunks (bool early)
704 {
705 struct cgraph_node *node;
706
707 FOR_EACH_DEFINED_FUNCTION (node)
708 {
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))
714 || !early))
715 {
716 node->release_body ();
717 node->remove_callees ();
718 node->remove_all_references ();
719
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,
725 IPA_REF_CHKP, NULL);
726 /* Thunk shouldn't be a cdtor. */
727 DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
728 DECL_STATIC_DESTRUCTOR (node->decl) = 0;
729 }
730 }
731
732 /* Mark instrumentation clones created for aliases and thunks
733 as insttrumented so they could be removed as unreachable
734 now. */
735 if (!early)
736 {
737 FOR_EACH_DEFINED_FUNCTION (node)
738 {
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);
743 }
744 }
745
746 return TODO_remove_functions;
747 }
748
749 const pass_data pass_data_ipa_chkp_versioning =
750 {
751 SIMPLE_IPA_PASS, /* type */
752 "chkp_versioning", /* name */
753 OPTGROUP_NONE, /* optinfo_flags */
754 TV_NONE, /* tv_id */
755 0, /* properties_required */
756 0, /* properties_provided */
757 0, /* properties_destroyed */
758 0, /* todo_flags_start */
759 0 /* todo_flags_finish */
760 };
761
762 const pass_data pass_data_ipa_chkp_early_produce_thunks =
763 {
764 SIMPLE_IPA_PASS, /* type */
765 "chkp_ecleanup", /* name */
766 OPTGROUP_NONE, /* optinfo_flags */
767 TV_NONE, /* tv_id */
768 0, /* properties_required */
769 0, /* properties_provided */
770 0, /* properties_destroyed */
771 0, /* todo_flags_start */
772 0 /* todo_flags_finish */
773 };
774
775 const pass_data pass_data_ipa_chkp_produce_thunks =
776 {
777 SIMPLE_IPA_PASS, /* type */
778 "chkp_cleanup", /* name */
779 OPTGROUP_NONE, /* optinfo_flags */
780 TV_NONE, /* tv_id */
781 0, /* properties_required */
782 0, /* properties_provided */
783 0, /* properties_destroyed */
784 0, /* todo_flags_start */
785 0 /* todo_flags_finish */
786 };
787
788 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
789 {
790 public:
791 pass_ipa_chkp_versioning (gcc::context *ctxt)
792 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
793 {}
794
795 /* opt_pass methods: */
796 virtual opt_pass * clone ()
797 {
798 return new pass_ipa_chkp_versioning (m_ctxt);
799 }
800
801 virtual bool gate (function *)
802 {
803 return flag_check_pointer_bounds;
804 }
805
806 virtual unsigned int execute (function *)
807 {
808 return chkp_versioning ();
809 }
810
811 }; // class pass_ipa_chkp_versioning
812
813 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
814 {
815 public:
816 pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
817 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
818 {}
819
820 /* opt_pass methods: */
821 virtual opt_pass * clone ()
822 {
823 return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
824 }
825
826 virtual bool gate (function *)
827 {
828 return flag_check_pointer_bounds;
829 }
830
831 virtual unsigned int execute (function *)
832 {
833 return chkp_produce_thunks (true);
834 }
835
836 }; // class pass_chkp_produce_thunks
837
838 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
839 {
840 public:
841 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
842 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
843 {}
844
845 /* opt_pass methods: */
846 virtual opt_pass * clone ()
847 {
848 return new pass_ipa_chkp_produce_thunks (m_ctxt);
849 }
850
851 virtual bool gate (function *)
852 {
853 return flag_check_pointer_bounds;
854 }
855
856 virtual unsigned int execute (function *)
857 {
858 return chkp_produce_thunks (false);
859 }
860
861 }; // class pass_chkp_produce_thunks
862
863 simple_ipa_opt_pass *
864 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
865 {
866 return new pass_ipa_chkp_versioning (ctxt);
867 }
868
869 simple_ipa_opt_pass *
870 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
871 {
872 return new pass_ipa_chkp_early_produce_thunks (ctxt);
873 }
874
875 simple_ipa_opt_pass *
876 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
877 {
878 return new pass_ipa_chkp_produce_thunks (ctxt);
879 }