coretypes.h: Include machmode.h...
[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 "hash-set.h"
25 #include "vec.h"
26 #include "input.h"
27 #include "alias.h"
28 #include "symtab.h"
29 #include "options.h"
30 #include "inchash.h"
31 #include "tree.h"
32 #include "fold-const.h"
33 #include "stor-layout.h"
34 #include "tree-pass.h"
35 #include "stringpool.h"
36 #include "bitmap.h"
37 #include "gimple-expr.h"
38 #include "tm.h"
39 #include "hard-reg-set.h"
40 #include "function.h"
41 #include "is-a.h"
42 #include "tree-ssa-alias.h"
43 #include "predict.h"
44 #include "basic-block.h"
45 #include "gimple.h"
46 #include "ipa-ref.h"
47 #include "lto-streamer.h"
48 #include "cgraph.h"
49 #include "tree-chkp.h"
50 #include "tree-inline.h"
51 #include "ipa-chkp.h"
52
53 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
54
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.
58
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.
65
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).
71
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.
77
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).
82
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.
88
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
97 removed. */
98
99 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
100 #define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
101
102 /* Return 1 calls to FNDECL should be replaced with
103 a call to wrapper function. */
104 bool
105 chkp_wrap_function (tree fndecl)
106 {
107 if (!flag_chkp_use_wrappers)
108 return false;
109
110 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
111 {
112 switch (DECL_FUNCTION_CODE (fndecl))
113 {
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:
125 case BUILT_IN_BZERO:
126 case BUILT_IN_MALLOC:
127 case BUILT_IN_CALLOC:
128 case BUILT_IN_REALLOC:
129 return 1;
130
131 default:
132 return 0;
133 }
134 }
135
136 return false;
137 }
138
139 static const char *
140 chkp_wrap_function_name (tree fndecl)
141 {
142 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL);
143
144 switch (DECL_FUNCTION_CODE (fndecl))
145 {
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";
168 case BUILT_IN_BZERO:
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";
176
177 default:
178 gcc_unreachable ();
179 }
180
181 return "";
182 }
183
184 /* Build a clone of FNDECL with a modified name. */
185
186 static tree
187 chkp_build_instrumented_fndecl (tree fndecl)
188 {
189 tree new_decl = copy_node (fndecl);
190 tree new_name;
191 std::string s;
192
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));
198 s += ".chkp";
199 DECL_NAME (new_decl) = get_identifier (s.c_str ());
200
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))
208 {
209 new_name = get_identifier (chkp_wrap_function_name (fndecl));
210 DECL_VISIBILITY (new_decl) = VISIBILITY_DEFAULT;
211 }
212 else
213 {
214 s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
215 s += ".chkp";
216 new_name = get_identifier (s.c_str ());
217 IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
218 TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
219 }
220 SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
221
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));
226
227 /* We are going to modify attributes list and therefore should
228 make own copy. */
229 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
230
231 /* Change builtin function code. */
232 if (DECL_BUILT_IN (new_decl))
233 {
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);
239 }
240
241 return new_decl;
242 }
243
244
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. */
249
250 static void
251 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
252 unsigned *indexes, int len, int delta)
253 {
254 tree attr = lookup_attribute (attr_name, attrs);
255 tree op;
256
257 if (!attr)
258 return;
259
260 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
261 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
262 {
263 int idx;
264
265 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
266 continue;
267
268 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
269
270 /* If idx exceeds indexes length then we just
271 keep it at the same distance from the last
272 known arg. */
273 if (idx > len)
274 idx += delta;
275 else
276 idx = indexes[idx - 1] + 1;
277 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
278 }
279 }
280
281 /* Make a copy of function type ORIG_TYPE adding pointer
282 bounds as additional arguments. */
283
284 tree
285 chkp_copy_function_type_adding_bounds (tree orig_type)
286 {
287 tree 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;
292
293 for (arg_type = TYPE_ARG_TYPES (orig_type);
294 arg_type;
295 arg_type = TREE_CHAIN (arg_type))
296 if (TREE_VALUE (arg_type) == void_type_node)
297 continue;
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)))
302 break;
303
304 /* We may use original type if there are no bounds passed. */
305 if (!arg_type)
306 return orig_type;
307
308 type = build_distinct_type_copy (orig_type);
309 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
310
311 for (arg_type = TYPE_ARG_TYPES (type);
312 arg_type;
313 arg_type = TREE_CHAIN (arg_type))
314 {
315 indexes[idx++] = new_idx++;
316
317 /* pass_by_reference returns 1 for void type,
318 so check for it first. */
319 if (TREE_VALUE (arg_type) == void_type_node)
320 continue;
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))
324 {
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;
329
330 arg_type = TREE_CHAIN (arg_type);
331 new_idx++;
332 }
333 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
334 {
335 bitmap slots = BITMAP_ALLOC (NULL);
336 bitmap_iterator bi;
337 unsigned bnd_no;
338
339 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
340
341 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
342 {
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;
347
348 arg_type = TREE_CHAIN (arg_type);
349 new_idx++;
350 }
351 BITMAP_FREE (slots);
352 }
353 }
354
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))
362 {
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;
369 }
370
371 return type;
372 }
373
374 /* For given function FNDECL add bounds arguments to arguments
375 list. */
376
377 static void
378 chkp_add_bounds_params_to_function (tree fndecl)
379 {
380 tree arg;
381
382 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
383 if (BOUNDED_P (arg))
384 {
385 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
386 tree new_arg;
387
388 if (DECL_NAME (arg))
389 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
390 else
391 {
392 char uid[25];
393 snprintf (uid, 25, "D.%u", DECL_UID (arg));
394 new_name += uid;
395 }
396
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;
405
406 arg = DECL_CHAIN (arg);
407
408 }
409 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
410 {
411 tree orig_arg = arg;
412 bitmap slots = BITMAP_ALLOC (NULL);
413 bitmap_iterator bi;
414 unsigned bnd_no;
415
416 chkp_find_bound_slots (TREE_TYPE (arg), slots);
417
418 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
419 {
420 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
421 tree new_arg;
422 char offs[25];
423
424 if (DECL_NAME (orig_arg))
425 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
426 else
427 {
428 snprintf (offs, 25, "D.%u", DECL_UID (arg));
429 new_name += offs;
430 }
431 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
432
433 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
434 PARM_DECL,
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;
442
443 arg = DECL_CHAIN (arg);
444 }
445 BITMAP_FREE (slots);
446 }
447
448 TREE_TYPE (fndecl) =
449 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
450 }
451
452 /* Return an instrumentation clone for builtin function
453 FNDECL. Create one if needed. */
454
455 tree
456 chkp_maybe_clone_builtin_fndecl (tree fndecl)
457 {
458 tree clone;
459 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
460
461 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
462 && fcode < BEGIN_CHKP_BUILTINS);
463
464 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
465 clone = builtin_decl_explicit (fcode);
466 if (clone)
467 return clone;
468
469 clone = chkp_build_instrumented_fndecl (fndecl);
470 chkp_add_bounds_params_to_function (clone);
471
472 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
473
474 set_builtin_decl (fcode, clone, false);
475
476 return clone;
477 }
478
479 /* Return 1 if function FNDECL should be instrumented. */
480
481 bool
482 chkp_instrumentable_p (tree fndecl)
483 {
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)));
489 }
490
491 /* Return clone created for instrumentation of NODE or NULL. */
492
493 cgraph_node *
494 chkp_maybe_create_clone (tree fndecl)
495 {
496 cgraph_node *node = cgraph_node::get_create (fndecl);
497 cgraph_node *clone = node->instrumented_version;
498
499 gcc_assert (!node->instrumentation_clone);
500
501 if (DECL_BUILT_IN (fndecl)
502 && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
503 || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
504 return NULL;
505
506 clone = node->instrumented_version;
507
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))
515 && !clone)
516 {
517 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
518 tree new_decl;
519
520 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
521 new_decl = builtin_decl_explicit (fncode);
522
523 /* We've actually already created an instrumented clone once.
524 Restore it. */
525 if (new_decl)
526 {
527 clone = cgraph_node::get (new_decl);
528
529 if (!clone)
530 {
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;
542 }
543
544 clone->instrumented_version = node;
545 node->instrumented_version = clone;
546 }
547 }
548
549 if (!clone)
550 {
551 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
552 struct cgraph_edge *e;
553 struct ipa_ref *ref;
554 int i;
555
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;
568
569 if (gimple_has_body_p (fndecl))
570 {
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))
574 {
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;
583 }
584 else
585 {
586 tree_function_versioning (fndecl, new_decl, NULL, false,
587 NULL, false, NULL, NULL);
588 clone->lowered = true;
589 }
590 }
591
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);
595
596 /* Remember builtin fndecl. */
597 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
598 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
599 {
600 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
601 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
602 clone->decl, false);
603 }
604
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);
610
611 if (gimple_has_body_p (fndecl))
612 symtab->call_cgraph_insertion_hooks (clone);
613
614 /* Clone all aliases. */
615 for (i = 0; node->iterate_direct_aliases (i, ref); i++)
616 chkp_maybe_create_clone (ref->referring->decl);
617
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)
623 {
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);
628 }
629
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)
635 {
636 struct cgraph_node *target;
637
638 ref = node->ref_list.first_reference ();
639 if (ref)
640 {
641 target = chkp_maybe_create_clone (ref->referred->decl);
642 clone->create_reference (target, IPA_REF_ALIAS);
643 }
644
645 if (node->alias_target)
646 {
647 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
648 {
649 target = chkp_maybe_create_clone (node->alias_target);
650 clone->alias_target = target->decl;
651 }
652 else
653 clone->alias_target = node->alias_target;
654 }
655 }
656
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);
660 }
661
662 return clone;
663 }
664
665 /* Create clone for all functions to be instrumented. */
666
667 static unsigned int
668 chkp_versioning (void)
669 {
670 struct cgraph_node *node;
671 const char *reason;
672
673 bitmap_obstack_initialize (NULL);
674
675 FOR_EACH_DEFINED_FUNCTION (node)
676 {
677 if (!node->instrumentation_clone
678 && !node->instrumented_version
679 && !node->alias
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)))
684 {
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),
688 node->decl)))
689 {
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);
693 }
694 }
695 }
696
697 /* Mark all aliases and thunks of functions with no instrumented
698 version as legacy function. */
699 FOR_EACH_DEFINED_FUNCTION (node)
700 {
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));
708 }
709
710 bitmap_obstack_release (NULL);
711
712 return 0;
713 }
714
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
719 function. */
720
721 static unsigned int
722 chkp_produce_thunks (bool early)
723 {
724 struct cgraph_node *node;
725
726 FOR_EACH_DEFINED_FUNCTION (node)
727 {
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))
733 || !early))
734 {
735 node->release_body ();
736 node->remove_callees ();
737 node->remove_all_references ();
738
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,
744 IPA_REF_CHKP, NULL);
745 /* Thunk shouldn't be a cdtor. */
746 DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
747 DECL_STATIC_DESTRUCTOR (node->decl) = 0;
748 }
749 }
750
751 /* Mark instrumentation clones created for aliases and thunks
752 as insttrumented so they could be removed as unreachable
753 now. */
754 if (!early)
755 {
756 FOR_EACH_DEFINED_FUNCTION (node)
757 {
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);
762 }
763 }
764
765 return TODO_remove_functions;
766 }
767
768 const pass_data pass_data_ipa_chkp_versioning =
769 {
770 SIMPLE_IPA_PASS, /* type */
771 "chkp_versioning", /* name */
772 OPTGROUP_NONE, /* optinfo_flags */
773 TV_NONE, /* tv_id */
774 0, /* properties_required */
775 0, /* properties_provided */
776 0, /* properties_destroyed */
777 0, /* todo_flags_start */
778 0 /* todo_flags_finish */
779 };
780
781 const pass_data pass_data_ipa_chkp_early_produce_thunks =
782 {
783 SIMPLE_IPA_PASS, /* type */
784 "chkp_ecleanup", /* name */
785 OPTGROUP_NONE, /* optinfo_flags */
786 TV_NONE, /* tv_id */
787 0, /* properties_required */
788 0, /* properties_provided */
789 0, /* properties_destroyed */
790 0, /* todo_flags_start */
791 0 /* todo_flags_finish */
792 };
793
794 const pass_data pass_data_ipa_chkp_produce_thunks =
795 {
796 SIMPLE_IPA_PASS, /* type */
797 "chkp_cleanup", /* name */
798 OPTGROUP_NONE, /* optinfo_flags */
799 TV_NONE, /* tv_id */
800 0, /* properties_required */
801 0, /* properties_provided */
802 0, /* properties_destroyed */
803 0, /* todo_flags_start */
804 0 /* todo_flags_finish */
805 };
806
807 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
808 {
809 public:
810 pass_ipa_chkp_versioning (gcc::context *ctxt)
811 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
812 {}
813
814 /* opt_pass methods: */
815 virtual opt_pass * clone ()
816 {
817 return new pass_ipa_chkp_versioning (m_ctxt);
818 }
819
820 virtual bool gate (function *)
821 {
822 return flag_check_pointer_bounds;
823 }
824
825 virtual unsigned int execute (function *)
826 {
827 return chkp_versioning ();
828 }
829
830 }; // class pass_ipa_chkp_versioning
831
832 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
833 {
834 public:
835 pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
836 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
837 {}
838
839 /* opt_pass methods: */
840 virtual opt_pass * clone ()
841 {
842 return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
843 }
844
845 virtual bool gate (function *)
846 {
847 return flag_check_pointer_bounds;
848 }
849
850 virtual unsigned int execute (function *)
851 {
852 return chkp_produce_thunks (true);
853 }
854
855 }; // class pass_chkp_produce_thunks
856
857 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
858 {
859 public:
860 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
861 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
862 {}
863
864 /* opt_pass methods: */
865 virtual opt_pass * clone ()
866 {
867 return new pass_ipa_chkp_produce_thunks (m_ctxt);
868 }
869
870 virtual bool gate (function *)
871 {
872 return flag_check_pointer_bounds;
873 }
874
875 virtual unsigned int execute (function *)
876 {
877 return chkp_produce_thunks (false);
878 }
879
880 }; // class pass_chkp_produce_thunks
881
882 simple_ipa_opt_pass *
883 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
884 {
885 return new pass_ipa_chkp_versioning (ctxt);
886 }
887
888 simple_ipa_opt_pass *
889 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
890 {
891 return new pass_ipa_chkp_early_produce_thunks (ctxt);
892 }
893
894 simple_ipa_opt_pass *
895 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
896 {
897 return new pass_ipa_chkp_produce_thunks (ctxt);
898 }