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