re PR target/69894 (dependency of gcc-plugin.h not installed on aarch64-linux-gnu)
[gcc.git] / gcc / ipa-chkp.c
1 /* Pointer Bounds Checker IPA passes.
2 Copyright (C) 2014-2016 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 #define INCLUDE_STRING
23 #include "system.h"
24 #include "coretypes.h"
25 #include "backend.h"
26 #include "tree.h"
27 #include "gimple.h"
28 #include "tree-pass.h"
29 #include "stringpool.h"
30 #include "lto-streamer.h"
31 #include "stor-layout.h"
32 #include "calls.h"
33 #include "cgraph.h"
34 #include "tree-chkp.h"
35 #include "tree-inline.h"
36 #include "ipa-chkp.h"
37
38 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
39
40 In instrumented code each pointer is provided with bounds. For input
41 pointer parameters it means we also have bounds passed. For calls it
42 means we have additional bounds arguments for pointer arguments.
43
44 To have all IPA optimizations working correctly we have to express
45 dataflow between passed and received bounds explicitly via additional
46 entries in function declaration arguments list and in function type.
47 Since we may have both instrumented and not instrumented code at the
48 same time, we cannot replace all original functions with their
49 instrumented variants. Therefore we create clones (versions) instead.
50
51 Instrumentation clones creation is a separate IPA pass which is a part
52 of early local passes. Clones are created after SSA is built (because
53 instrumentation pass works on SSA) and before any transformations
54 which may change pointer flow and therefore lead to incorrect code
55 instrumentation (possibly causing false bounds check failures).
56
57 Instrumentation clones have pointer bounds arguments added right after
58 pointer arguments. Clones have assembler name of the original
59 function with suffix added. New assembler name is in transparent
60 alias chain with the original name. Thus we expect all calls to the
61 original and instrumented functions look similar in assembler.
62
63 During instrumentation versioning pass we create instrumented versions
64 of all function with body and also for all their aliases and thunks.
65 Clones for functions with no body are created on demand (usually
66 during call instrumentation).
67
68 Original and instrumented function nodes are connected with IPA
69 reference IPA_REF_CHKP. It is mostly done to have reachability
70 analysis working correctly. We may have no references to the
71 instrumented function in the code but it still should be counted
72 as reachable if the original function is reachable.
73
74 When original function bodies are not needed anymore we release
75 them and transform functions into a special kind of thunks. Each
76 thunk has a call edge to the instrumented version. These thunks
77 help to keep externally visible instrumented functions visible
78 when linker resolution files are used. Linker has no info about
79 connection between original and instrumented function and
80 therefore we may wrongly decide (due to difference in assembler
81 names) that instrumented function version is local and can be
82 removed. */
83
84 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
85 #define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
86
87 /* Return 1 calls to FNDECL should be replaced with
88 a call to wrapper function. */
89 bool
90 chkp_wrap_function (tree fndecl)
91 {
92 if (!flag_chkp_use_wrappers)
93 return false;
94
95 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
96 {
97 switch (DECL_FUNCTION_CODE (fndecl))
98 {
99 case BUILT_IN_STRLEN:
100 case BUILT_IN_STRCPY:
101 case BUILT_IN_STRNCPY:
102 case BUILT_IN_STPCPY:
103 case BUILT_IN_STPNCPY:
104 case BUILT_IN_STRCAT:
105 case BUILT_IN_STRNCAT:
106 case BUILT_IN_MEMCPY:
107 case BUILT_IN_MEMPCPY:
108 case BUILT_IN_MEMSET:
109 case BUILT_IN_MEMMOVE:
110 case BUILT_IN_BZERO:
111 case BUILT_IN_MALLOC:
112 case BUILT_IN_CALLOC:
113 case BUILT_IN_REALLOC:
114 return 1;
115
116 default:
117 return 0;
118 }
119 }
120
121 return false;
122 }
123
124 static const char *
125 chkp_wrap_function_name (tree fndecl)
126 {
127 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL);
128
129 switch (DECL_FUNCTION_CODE (fndecl))
130 {
131 case BUILT_IN_STRLEN:
132 return CHKP_WRAPPER_SYMBOL_PREFIX "strlen";
133 case BUILT_IN_STRCPY:
134 return CHKP_WRAPPER_SYMBOL_PREFIX "strcpy";
135 case BUILT_IN_STRNCPY:
136 return CHKP_WRAPPER_SYMBOL_PREFIX "strncpy";
137 case BUILT_IN_STPCPY:
138 return CHKP_WRAPPER_SYMBOL_PREFIX "stpcpy";
139 case BUILT_IN_STPNCPY:
140 return CHKP_WRAPPER_SYMBOL_PREFIX "stpncpy";
141 case BUILT_IN_STRCAT:
142 return CHKP_WRAPPER_SYMBOL_PREFIX "strcat";
143 case BUILT_IN_STRNCAT:
144 return CHKP_WRAPPER_SYMBOL_PREFIX "strncat";
145 case BUILT_IN_MEMCPY:
146 return CHKP_WRAPPER_SYMBOL_PREFIX "memcpy";
147 case BUILT_IN_MEMPCPY:
148 return CHKP_WRAPPER_SYMBOL_PREFIX "mempcpy";
149 case BUILT_IN_MEMSET:
150 return CHKP_WRAPPER_SYMBOL_PREFIX "memset";
151 case BUILT_IN_MEMMOVE:
152 return CHKP_WRAPPER_SYMBOL_PREFIX "memmove";
153 case BUILT_IN_BZERO:
154 return CHKP_WRAPPER_SYMBOL_PREFIX "bzero";
155 case BUILT_IN_MALLOC:
156 return CHKP_WRAPPER_SYMBOL_PREFIX "malloc";
157 case BUILT_IN_CALLOC:
158 return CHKP_WRAPPER_SYMBOL_PREFIX "calloc";
159 case BUILT_IN_REALLOC:
160 return CHKP_WRAPPER_SYMBOL_PREFIX "realloc";
161
162 default:
163 gcc_unreachable ();
164 }
165
166 return "";
167 }
168
169 /* Build a clone of FNDECL with a modified name. */
170
171 static tree
172 chkp_build_instrumented_fndecl (tree fndecl)
173 {
174 tree new_decl = copy_node (fndecl);
175 tree new_name;
176 std::string s;
177
178 /* called_as_built_in checks DECL_NAME to identify calls to
179 builtins. We want instrumented calls to builtins to be
180 recognized by called_as_built_in. Therefore use original
181 DECL_NAME for cloning with no prefixes. */
182 s = IDENTIFIER_POINTER (DECL_NAME (fndecl));
183 s += ".chkp";
184 DECL_NAME (new_decl) = get_identifier (s.c_str ());
185
186 /* References to the original and to the instrumented version
187 should look the same in the output assembly. And we cannot
188 use the same assembler name for the instrumented version
189 because it conflicts with decl merging algorithms in LTO.
190 Achieve the result by using transparent alias name for the
191 instrumented version. */
192 if (chkp_wrap_function(fndecl))
193 {
194 new_name = get_identifier (chkp_wrap_function_name (fndecl));
195 DECL_VISIBILITY (new_decl) = VISIBILITY_DEFAULT;
196 }
197 else
198 {
199 s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
200 s += ".chkp";
201 new_name = get_identifier (s.c_str ());
202 IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
203 TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
204 }
205 SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
206
207 /* For functions with body versioning will make a copy of arguments.
208 For functions with no body we need to do it here. */
209 if (!gimple_has_body_p (fndecl))
210 DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
211
212 /* We are going to modify attributes list and therefore should
213 make own copy. */
214 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
215
216 /* Change builtin function code. */
217 if (DECL_BUILT_IN (new_decl))
218 {
219 gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL);
220 gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS);
221 DECL_FUNCTION_CODE (new_decl)
222 = (enum built_in_function)(DECL_FUNCTION_CODE (new_decl)
223 + BEGIN_CHKP_BUILTINS + 1);
224 }
225
226 return new_decl;
227 }
228
229
230 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
231 Integer operands are replaced with values according to
232 INDEXES map having LEN elements. For operands out of len
233 we just add DELTA. */
234
235 static void
236 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
237 unsigned *indexes, int len, int delta)
238 {
239 tree attr = lookup_attribute (attr_name, attrs);
240 tree op;
241
242 if (!attr)
243 return;
244
245 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
246 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
247 {
248 int idx;
249
250 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
251 continue;
252
253 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
254
255 /* If idx exceeds indexes length then we just
256 keep it at the same distance from the last
257 known arg. */
258 if (idx > len)
259 idx += delta;
260 else
261 idx = indexes[idx - 1] + 1;
262 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
263 }
264 }
265
266 /* Make a copy of function type ORIG_TYPE adding pointer
267 bounds as additional arguments. */
268
269 tree
270 chkp_copy_function_type_adding_bounds (tree orig_type)
271 {
272 tree type;
273 tree arg_type, attrs;
274 unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
275 unsigned *indexes = XALLOCAVEC (unsigned, len);
276 unsigned idx = 0, new_idx = 0;
277
278 for (arg_type = TYPE_ARG_TYPES (orig_type);
279 arg_type;
280 arg_type = TREE_CHAIN (arg_type))
281 if (TREE_VALUE (arg_type) == void_type_node)
282 continue;
283 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
284 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
285 TREE_VALUE (arg_type), true)
286 || chkp_type_has_pointer (TREE_VALUE (arg_type)))
287 break;
288
289 /* We may use original type if there are no bounds passed. */
290 if (!arg_type)
291 return orig_type;
292
293 type = build_distinct_type_copy (orig_type);
294 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
295
296 for (arg_type = TYPE_ARG_TYPES (type);
297 arg_type;
298 arg_type = TREE_CHAIN (arg_type))
299 {
300 indexes[idx++] = new_idx++;
301
302 /* pass_by_reference returns 1 for void type,
303 so check for it first. */
304 if (TREE_VALUE (arg_type) == void_type_node)
305 continue;
306 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
307 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
308 TREE_VALUE (arg_type), true))
309 {
310 tree new_type = build_tree_list (NULL_TREE,
311 pointer_bounds_type_node);
312 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
313 TREE_CHAIN (arg_type) = new_type;
314
315 arg_type = TREE_CHAIN (arg_type);
316 new_idx++;
317 }
318 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
319 {
320 bitmap slots = BITMAP_ALLOC (NULL);
321 bitmap_iterator bi;
322 unsigned bnd_no;
323
324 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
325
326 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
327 {
328 tree new_type = build_tree_list (NULL_TREE,
329 pointer_bounds_type_node);
330 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
331 TREE_CHAIN (arg_type) = new_type;
332
333 arg_type = TREE_CHAIN (arg_type);
334 new_idx++;
335 }
336 BITMAP_FREE (slots);
337 }
338 }
339
340 /* If function type has attribute with arg indexes then
341 we have to copy it fixing attribute ops. Map for
342 fixing is in indexes array. */
343 attrs = TYPE_ATTRIBUTES (type);
344 if (lookup_attribute ("nonnull", attrs)
345 || lookup_attribute ("format", attrs)
346 || lookup_attribute ("format_arg", attrs))
347 {
348 int delta = new_idx - len;
349 attrs = copy_list (TYPE_ATTRIBUTES (type));
350 chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
351 chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
352 chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
353 TYPE_ATTRIBUTES (type) = attrs;
354 }
355
356 return type;
357 }
358
359 /* For given function FNDECL add bounds arguments to arguments
360 list. */
361
362 static void
363 chkp_add_bounds_params_to_function (tree fndecl)
364 {
365 tree arg;
366
367 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
368 if (BOUNDED_P (arg))
369 {
370 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
371 tree new_arg;
372
373 if (DECL_NAME (arg))
374 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
375 else
376 {
377 char uid[25];
378 snprintf (uid, 25, "D.%u", DECL_UID (arg));
379 new_name += uid;
380 }
381
382 new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
383 get_identifier (new_name.c_str ()),
384 pointer_bounds_type_node);
385 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
386 DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
387 DECL_ARTIFICIAL (new_arg) = 1;
388 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
389 DECL_CHAIN (arg) = new_arg;
390
391 arg = DECL_CHAIN (arg);
392
393 }
394 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
395 {
396 tree orig_arg = arg;
397 bitmap slots = BITMAP_ALLOC (NULL);
398 bitmap_iterator bi;
399 unsigned bnd_no;
400
401 chkp_find_bound_slots (TREE_TYPE (arg), slots);
402
403 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
404 {
405 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
406 tree new_arg;
407 char offs[25];
408
409 if (DECL_NAME (orig_arg))
410 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
411 else
412 {
413 snprintf (offs, 25, "D.%u", DECL_UID (arg));
414 new_name += offs;
415 }
416 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
417
418 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
419 PARM_DECL,
420 get_identifier (new_name.c_str ()),
421 pointer_bounds_type_node);
422 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
423 DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
424 DECL_ARTIFICIAL (new_arg) = 1;
425 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
426 DECL_CHAIN (arg) = new_arg;
427
428 arg = DECL_CHAIN (arg);
429 }
430 BITMAP_FREE (slots);
431 }
432
433 TREE_TYPE (fndecl) =
434 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
435 }
436
437 /* Return an instrumentation clone for builtin function
438 FNDECL. Create one if needed. */
439
440 tree
441 chkp_maybe_clone_builtin_fndecl (tree fndecl)
442 {
443 tree clone;
444 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
445
446 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
447 && fcode < BEGIN_CHKP_BUILTINS);
448
449 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
450 clone = builtin_decl_explicit (fcode);
451 if (clone)
452 return clone;
453
454 clone = chkp_build_instrumented_fndecl (fndecl);
455 chkp_add_bounds_params_to_function (clone);
456
457 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
458
459 set_builtin_decl (fcode, clone, false);
460
461 return clone;
462 }
463
464 /* Return 1 if function FNDECL should be instrumented. */
465
466 bool
467 chkp_instrumentable_p (tree fndecl)
468 {
469 struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
470 return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
471 && (!flag_chkp_instrument_marked_only
472 || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl)))
473 && (!fn || !copy_forbidden (fn, fndecl)));
474 }
475
476 /* Return clone created for instrumentation of NODE or NULL. */
477
478 cgraph_node *
479 chkp_maybe_create_clone (tree fndecl)
480 {
481 cgraph_node *node = cgraph_node::get_create (fndecl);
482 cgraph_node *clone = node->instrumented_version;
483
484 gcc_assert (!node->instrumentation_clone);
485
486 if (DECL_BUILT_IN (fndecl)
487 && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
488 || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
489 return NULL;
490
491 clone = node->instrumented_version;
492
493 /* Some instrumented builtin function calls may be optimized and
494 cgraph nodes may be removed as unreachable. Later optimizations
495 may generate new calls to removed functions and in this case
496 we have to recreate cgraph node. FUNCTION_DECL for instrumented
497 builtin still exists and should be reused in such case. */
498 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
499 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))
500 && !clone)
501 {
502 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
503 tree new_decl;
504
505 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
506 new_decl = builtin_decl_explicit (fncode);
507
508 /* We've actually already created an instrumented clone once.
509 Restore it. */
510 if (new_decl)
511 {
512 clone = cgraph_node::get (new_decl);
513
514 if (!clone)
515 {
516 gcc_assert (!gimple_has_body_p (fndecl));
517 clone = cgraph_node::get_create (new_decl);
518 clone->externally_visible = node->externally_visible;
519 clone->local = node->local;
520 clone->address_taken = node->address_taken;
521 clone->thunk = node->thunk;
522 clone->alias = node->alias;
523 clone->weakref = node->weakref;
524 clone->cpp_implicit_alias = node->cpp_implicit_alias;
525 clone->orig_decl = fndecl;
526 clone->instrumentation_clone = true;
527 }
528
529 clone->instrumented_version = node;
530 node->instrumented_version = clone;
531 }
532 }
533
534 if (!clone)
535 {
536 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
537 struct cgraph_edge *e;
538 struct ipa_ref *ref;
539 int i;
540
541 clone = node->create_version_clone (new_decl, vNULL, NULL);
542 clone->externally_visible = node->externally_visible;
543 clone->local = node->local;
544 clone->address_taken = node->address_taken;
545 clone->thunk = node->thunk;
546 clone->alias = node->alias;
547 clone->weakref = node->weakref;
548 clone->cpp_implicit_alias = node->cpp_implicit_alias;
549 clone->instrumented_version = node;
550 clone->orig_decl = fndecl;
551 clone->instrumentation_clone = true;
552 node->instrumented_version = clone;
553
554 if (gimple_has_body_p (fndecl))
555 {
556 gcc_assert (chkp_instrumentable_p (fndecl));
557 tree_function_versioning (fndecl, new_decl, NULL, false,
558 NULL, false, NULL, NULL);
559 clone->lowered = true;
560 }
561
562 /* New params are inserted after versioning because it
563 actually copies args list from the original decl. */
564 chkp_add_bounds_params_to_function (new_decl);
565
566 /* Remember builtin fndecl. */
567 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
568 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
569 {
570 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
571 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
572 clone->decl, false);
573 }
574
575 /* Clones have the same comdat group as originals. */
576 if (node->same_comdat_group
577 || (DECL_ONE_ONLY (node->decl)
578 && !DECL_EXTERNAL (node->decl)))
579 clone->add_to_same_comdat_group (node);
580
581 if (gimple_has_body_p (fndecl))
582 symtab->call_cgraph_insertion_hooks (clone);
583
584 /* Clone all aliases. */
585 for (i = 0; node->iterate_direct_aliases (i, ref); i++)
586 chkp_maybe_create_clone (ref->referring->decl);
587
588 /* Clone all thunks. */
589 for (e = node->callers; e; e = e->next_caller)
590 if (e->caller->thunk.thunk_p
591 && !e->caller->thunk.add_pointer_bounds_args
592 && !e->caller->instrumentation_clone)
593 {
594 struct cgraph_node *thunk
595 = chkp_maybe_create_clone (e->caller->decl);
596 /* Redirect thunk clone edge to the node clone. */
597 thunk->callees->redirect_callee (clone);
598 }
599
600 /* For aliases and thunks we should make sure target is cloned
601 to have proper references and edges. */
602 if (node->thunk.thunk_p)
603 chkp_maybe_create_clone (node->callees->callee->decl);
604 else if (node->alias)
605 {
606 struct cgraph_node *target;
607
608 ref = node->ref_list.first_reference ();
609 if (ref)
610 {
611 target = chkp_maybe_create_clone (ref->referred->decl);
612 clone->create_reference (target, IPA_REF_ALIAS);
613 }
614
615 if (node->alias_target)
616 {
617 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
618 {
619 target = chkp_maybe_create_clone (node->alias_target);
620 clone->alias_target = target->decl;
621 }
622 else
623 clone->alias_target = node->alias_target;
624 }
625 }
626
627 /* Add IPA reference. It's main role is to keep instrumented
628 version reachable while original node is reachable. */
629 ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
630 }
631
632 return clone;
633 }
634
635 /* Create clone for all functions to be instrumented. */
636
637 static unsigned int
638 chkp_versioning (void)
639 {
640 struct cgraph_node *node;
641 const char *reason;
642
643 bitmap_obstack_initialize (NULL);
644
645 FOR_EACH_DEFINED_FUNCTION (node)
646 {
647 if (!node->instrumentation_clone
648 && !node->instrumented_version
649 && !node->alias
650 && !node->thunk.thunk_p
651 && (!DECL_BUILT_IN (node->decl)
652 || (DECL_BUILT_IN_CLASS (node->decl) == BUILT_IN_NORMAL
653 && DECL_FUNCTION_CODE (node->decl) < BEGIN_CHKP_BUILTINS)))
654 {
655 if (chkp_instrumentable_p (node->decl))
656 chkp_maybe_create_clone (node->decl);
657 else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl),
658 node->decl)))
659 {
660 if (warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wchkp,
661 "function cannot be instrumented"))
662 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
663 }
664 }
665 }
666
667 /* Mark all aliases and thunks of functions with no instrumented
668 version as legacy function. */
669 FOR_EACH_DEFINED_FUNCTION (node)
670 {
671 if (!node->instrumentation_clone
672 && !node->instrumented_version
673 && (node->alias || node->thunk.thunk_p)
674 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
675 DECL_ATTRIBUTES (node->decl)
676 = tree_cons (get_identifier ("bnd_legacy"), NULL,
677 DECL_ATTRIBUTES (node->decl));
678 }
679
680 bitmap_obstack_release (NULL);
681
682 return 0;
683 }
684
685 /* In this pass we remove bodies of functions having
686 instrumented version. Functions with removed bodies
687 become a special kind of thunks to provide a connection
688 between calls to the original version and instrumented
689 function. */
690
691 static unsigned int
692 chkp_produce_thunks (bool early)
693 {
694 struct cgraph_node *node;
695
696 FOR_EACH_DEFINED_FUNCTION (node)
697 {
698 if (!node->instrumentation_clone
699 && node->instrumented_version
700 && gimple_has_body_p (node->decl)
701 && gimple_has_body_p (node->instrumented_version->decl)
702 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
703 || !early))
704 {
705 node->release_body ();
706 node->remove_callees ();
707 node->remove_all_references ();
708
709 node->thunk.thunk_p = true;
710 node->thunk.add_pointer_bounds_args = true;
711 node->create_edge (node->instrumented_version, NULL,
712 0, CGRAPH_FREQ_BASE);
713 node->create_reference (node->instrumented_version,
714 IPA_REF_CHKP, NULL);
715 /* Thunk shouldn't be a cdtor. */
716 DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
717 DECL_STATIC_DESTRUCTOR (node->decl) = 0;
718 }
719 }
720
721 /* Mark instrumentation clones created for aliases and thunks
722 as insttrumented so they could be removed as unreachable
723 now. */
724 if (!early)
725 {
726 FOR_EACH_DEFINED_FUNCTION (node)
727 {
728 if (node->instrumentation_clone
729 && (node->alias || node->thunk.thunk_p)
730 && !chkp_function_instrumented_p (node->decl))
731 chkp_function_mark_instrumented (node->decl);
732 }
733 }
734
735 return TODO_remove_functions;
736 }
737
738 const pass_data pass_data_ipa_chkp_versioning =
739 {
740 SIMPLE_IPA_PASS, /* type */
741 "chkp_versioning", /* name */
742 OPTGROUP_NONE, /* optinfo_flags */
743 TV_NONE, /* tv_id */
744 0, /* properties_required */
745 0, /* properties_provided */
746 0, /* properties_destroyed */
747 0, /* todo_flags_start */
748 0 /* todo_flags_finish */
749 };
750
751 const pass_data pass_data_ipa_chkp_early_produce_thunks =
752 {
753 SIMPLE_IPA_PASS, /* type */
754 "chkp_ecleanup", /* name */
755 OPTGROUP_NONE, /* optinfo_flags */
756 TV_NONE, /* tv_id */
757 0, /* properties_required */
758 0, /* properties_provided */
759 0, /* properties_destroyed */
760 0, /* todo_flags_start */
761 0 /* todo_flags_finish */
762 };
763
764 const pass_data pass_data_ipa_chkp_produce_thunks =
765 {
766 SIMPLE_IPA_PASS, /* type */
767 "chkp_cleanup", /* name */
768 OPTGROUP_NONE, /* optinfo_flags */
769 TV_NONE, /* tv_id */
770 0, /* properties_required */
771 0, /* properties_provided */
772 0, /* properties_destroyed */
773 0, /* todo_flags_start */
774 0 /* todo_flags_finish */
775 };
776
777 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
778 {
779 public:
780 pass_ipa_chkp_versioning (gcc::context *ctxt)
781 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
782 {}
783
784 /* opt_pass methods: */
785 virtual opt_pass * clone ()
786 {
787 return new pass_ipa_chkp_versioning (m_ctxt);
788 }
789
790 virtual bool gate (function *)
791 {
792 return flag_check_pointer_bounds;
793 }
794
795 virtual unsigned int execute (function *)
796 {
797 return chkp_versioning ();
798 }
799
800 }; // class pass_ipa_chkp_versioning
801
802 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
803 {
804 public:
805 pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
806 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
807 {}
808
809 /* opt_pass methods: */
810 virtual opt_pass * clone ()
811 {
812 return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
813 }
814
815 virtual bool gate (function *)
816 {
817 return flag_check_pointer_bounds;
818 }
819
820 virtual unsigned int execute (function *)
821 {
822 return chkp_produce_thunks (true);
823 }
824
825 }; // class pass_chkp_produce_thunks
826
827 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
828 {
829 public:
830 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
831 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
832 {}
833
834 /* opt_pass methods: */
835 virtual opt_pass * clone ()
836 {
837 return new pass_ipa_chkp_produce_thunks (m_ctxt);
838 }
839
840 virtual bool gate (function *)
841 {
842 return flag_check_pointer_bounds;
843 }
844
845 virtual unsigned int execute (function *)
846 {
847 return chkp_produce_thunks (false);
848 }
849
850 }; // class pass_chkp_produce_thunks
851
852 simple_ipa_opt_pass *
853 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
854 {
855 return new pass_ipa_chkp_versioning (ctxt);
856 }
857
858 simple_ipa_opt_pass *
859 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
860 {
861 return new pass_ipa_chkp_early_produce_thunks (ctxt);
862 }
863
864 simple_ipa_opt_pass *
865 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
866 {
867 return new pass_ipa_chkp_produce_thunks (ctxt);
868 }