]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/ipa-chkp.c
.
[thirdparty/gcc.git] / gcc / ipa-chkp.c
CommitLineData
058a1b7a 1/* Pointer Bounds Checker IPA passes.
aad93da1 2 Copyright (C) 2014-2017 Free Software Foundation, Inc.
058a1b7a 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"
e1b9f860 22#define INCLUDE_STRING
058a1b7a 23#include "system.h"
24#include "coretypes.h"
9ef16211 25#include "backend.h"
058a1b7a 26#include "tree.h"
9ef16211 27#include "gimple.h"
058a1b7a 28#include "tree-pass.h"
29#include "stringpool.h"
058a1b7a 30#include "lto-streamer.h"
7c29e30e 31#include "stor-layout.h"
32#include "calls.h"
058a1b7a 33#include "cgraph.h"
34#include "tree-chkp.h"
66124ce7 35#include "tree-inline.h"
058a1b7a 36#include "ipa-chkp.h"
30a86690 37#include "stringpool.h"
38#include "attribs.h"
058a1b7a 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_"
4cefd7f7 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. */
9664a778 91bool
4cefd7f7 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}
058a1b7a 125
9664a778 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
058a1b7a 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. */
4cefd7f7 194 if (chkp_wrap_function(fndecl))
195 {
9664a778 196 new_name = get_identifier (chkp_wrap_function_name (fndecl));
197 DECL_VISIBILITY (new_decl) = VISIBILITY_DEFAULT;
4cefd7f7 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 }
058a1b7a 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))
3ec40531 212 {
213 tree arg;
214
215 DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
216 for (arg = DECL_ARGUMENTS (new_decl); arg; arg = DECL_CHAIN (arg))
217 DECL_CONTEXT (arg) = new_decl;
218 }
058a1b7a 219
220 /* We are going to modify attributes list and therefore should
221 make own copy. */
222 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
223
f21337ef 224 /* Change builtin function code. */
225 if (DECL_BUILT_IN (new_decl))
226 {
227 gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL);
228 gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS);
229 DECL_FUNCTION_CODE (new_decl)
230 = (enum built_in_function)(DECL_FUNCTION_CODE (new_decl)
231 + BEGIN_CHKP_BUILTINS + 1);
232 }
233
058a1b7a 234 return new_decl;
235}
236
237
238/* Fix operands of attribute from ATTRS list named ATTR_NAME.
239 Integer operands are replaced with values according to
240 INDEXES map having LEN elements. For operands out of len
241 we just add DELTA. */
242
243static void
244chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
245 unsigned *indexes, int len, int delta)
246{
247 tree attr = lookup_attribute (attr_name, attrs);
248 tree op;
249
250 if (!attr)
251 return;
252
253 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
254 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
255 {
256 int idx;
257
258 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
259 continue;
260
261 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
262
263 /* If idx exceeds indexes length then we just
264 keep it at the same distance from the last
265 known arg. */
266 if (idx > len)
267 idx += delta;
268 else
269 idx = indexes[idx - 1] + 1;
270 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
271 }
272}
273
274/* Make a copy of function type ORIG_TYPE adding pointer
275 bounds as additional arguments. */
276
277tree
278chkp_copy_function_type_adding_bounds (tree orig_type)
279{
280 tree type;
988cf7b9 281 tree arg_type, attrs;
058a1b7a 282 unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
283 unsigned *indexes = XALLOCAVEC (unsigned, len);
284 unsigned idx = 0, new_idx = 0;
285
286 for (arg_type = TYPE_ARG_TYPES (orig_type);
287 arg_type;
288 arg_type = TREE_CHAIN (arg_type))
289 if (TREE_VALUE (arg_type) == void_type_node)
290 continue;
291 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
292 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
293 TREE_VALUE (arg_type), true)
294 || chkp_type_has_pointer (TREE_VALUE (arg_type)))
295 break;
296
297 /* We may use original type if there are no bounds passed. */
298 if (!arg_type)
299 return orig_type;
300
cf6a4316 301 type = build_distinct_type_copy (orig_type);
058a1b7a 302 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
303
304 for (arg_type = TYPE_ARG_TYPES (type);
305 arg_type;
306 arg_type = TREE_CHAIN (arg_type))
307 {
308 indexes[idx++] = new_idx++;
309
310 /* pass_by_reference returns 1 for void type,
311 so check for it first. */
312 if (TREE_VALUE (arg_type) == void_type_node)
313 continue;
314 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
315 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
316 TREE_VALUE (arg_type), true))
317 {
318 tree new_type = build_tree_list (NULL_TREE,
319 pointer_bounds_type_node);
320 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
321 TREE_CHAIN (arg_type) = new_type;
322
323 arg_type = TREE_CHAIN (arg_type);
324 new_idx++;
325 }
326 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
327 {
328 bitmap slots = BITMAP_ALLOC (NULL);
329 bitmap_iterator bi;
330 unsigned bnd_no;
331
332 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
333
334 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
335 {
336 tree new_type = build_tree_list (NULL_TREE,
337 pointer_bounds_type_node);
338 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
339 TREE_CHAIN (arg_type) = new_type;
340
341 arg_type = TREE_CHAIN (arg_type);
342 new_idx++;
343 }
344 BITMAP_FREE (slots);
345 }
346 }
347
348 /* If function type has attribute with arg indexes then
349 we have to copy it fixing attribute ops. Map for
350 fixing is in indexes array. */
351 attrs = TYPE_ATTRIBUTES (type);
352 if (lookup_attribute ("nonnull", attrs)
353 || lookup_attribute ("format", attrs)
354 || lookup_attribute ("format_arg", attrs))
355 {
356 int delta = new_idx - len;
357 attrs = copy_list (TYPE_ATTRIBUTES (type));
358 chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
359 chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
360 chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
361 TYPE_ATTRIBUTES (type) = attrs;
362 }
363
058a1b7a 364 return type;
365}
366
367/* For given function FNDECL add bounds arguments to arguments
368 list. */
369
370static void
371chkp_add_bounds_params_to_function (tree fndecl)
372{
373 tree arg;
374
375 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
376 if (BOUNDED_P (arg))
377 {
378 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
379 tree new_arg;
380
381 if (DECL_NAME (arg))
382 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
383 else
384 {
385 char uid[25];
386 snprintf (uid, 25, "D.%u", DECL_UID (arg));
387 new_name += uid;
388 }
389
390 new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
391 get_identifier (new_name.c_str ()),
392 pointer_bounds_type_node);
393 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
394 DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
395 DECL_ARTIFICIAL (new_arg) = 1;
396 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
397 DECL_CHAIN (arg) = new_arg;
398
399 arg = DECL_CHAIN (arg);
400
401 }
402 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
403 {
404 tree orig_arg = arg;
405 bitmap slots = BITMAP_ALLOC (NULL);
406 bitmap_iterator bi;
407 unsigned bnd_no;
408
409 chkp_find_bound_slots (TREE_TYPE (arg), slots);
410
411 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
412 {
413 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
414 tree new_arg;
415 char offs[25];
416
417 if (DECL_NAME (orig_arg))
418 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
419 else
420 {
421 snprintf (offs, 25, "D.%u", DECL_UID (arg));
422 new_name += offs;
423 }
424 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
425
426 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
427 PARM_DECL,
428 get_identifier (new_name.c_str ()),
429 pointer_bounds_type_node);
430 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
431 DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
432 DECL_ARTIFICIAL (new_arg) = 1;
433 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
434 DECL_CHAIN (arg) = new_arg;
435
436 arg = DECL_CHAIN (arg);
437 }
438 BITMAP_FREE (slots);
439 }
440
441 TREE_TYPE (fndecl) =
442 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
443}
444
f21337ef 445/* Return an instrumentation clone for builtin function
446 FNDECL. Create one if needed. */
447
448tree
449chkp_maybe_clone_builtin_fndecl (tree fndecl)
450{
451 tree clone;
452 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
453
454 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
455 && fcode < BEGIN_CHKP_BUILTINS);
456
457 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
458 clone = builtin_decl_explicit (fcode);
459 if (clone)
460 return clone;
461
462 clone = chkp_build_instrumented_fndecl (fndecl);
463 chkp_add_bounds_params_to_function (clone);
464
465 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
466
467 set_builtin_decl (fcode, clone, false);
468
469 return clone;
470}
471
66124ce7 472/* Return 1 if function FNDECL should be instrumented. */
473
474bool
475chkp_instrumentable_p (tree fndecl)
476{
477 struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
478 return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
479 && (!flag_chkp_instrument_marked_only
480 || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl)))
37af779a 481 && (!fn || !copy_forbidden (fn)));
66124ce7 482}
483
058a1b7a 484/* Return clone created for instrumentation of NODE or NULL. */
485
486cgraph_node *
487chkp_maybe_create_clone (tree fndecl)
488{
489 cgraph_node *node = cgraph_node::get_create (fndecl);
490 cgraph_node *clone = node->instrumented_version;
491
492 gcc_assert (!node->instrumentation_clone);
493
f21337ef 494 if (DECL_BUILT_IN (fndecl)
495 && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
496 || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
497 return NULL;
498
499 clone = node->instrumented_version;
500
501 /* Some instrumented builtin function calls may be optimized and
502 cgraph nodes may be removed as unreachable. Later optimizations
503 may generate new calls to removed functions and in this case
504 we have to recreate cgraph node. FUNCTION_DECL for instrumented
505 builtin still exists and should be reused in such case. */
506 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
507 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))
508 && !clone)
509 {
510 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
511 tree new_decl;
512
513 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
514 new_decl = builtin_decl_explicit (fncode);
515
516 /* We've actually already created an instrumented clone once.
517 Restore it. */
518 if (new_decl)
519 {
520 clone = cgraph_node::get (new_decl);
521
522 if (!clone)
523 {
524 gcc_assert (!gimple_has_body_p (fndecl));
525 clone = cgraph_node::get_create (new_decl);
526 clone->externally_visible = node->externally_visible;
527 clone->local = node->local;
528 clone->address_taken = node->address_taken;
529 clone->thunk = node->thunk;
530 clone->alias = node->alias;
531 clone->weakref = node->weakref;
532 clone->cpp_implicit_alias = node->cpp_implicit_alias;
533 clone->orig_decl = fndecl;
534 clone->instrumentation_clone = true;
535 }
536
537 clone->instrumented_version = node;
538 node->instrumented_version = clone;
539 }
540 }
541
058a1b7a 542 if (!clone)
543 {
544 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
545 struct cgraph_edge *e;
546 struct ipa_ref *ref;
547 int i;
548
549 clone = node->create_version_clone (new_decl, vNULL, NULL);
550 clone->externally_visible = node->externally_visible;
551 clone->local = node->local;
552 clone->address_taken = node->address_taken;
553 clone->thunk = node->thunk;
554 clone->alias = node->alias;
555 clone->weakref = node->weakref;
556 clone->cpp_implicit_alias = node->cpp_implicit_alias;
557 clone->instrumented_version = node;
558 clone->orig_decl = fndecl;
559 clone->instrumentation_clone = true;
560 node->instrumented_version = clone;
561
562 if (gimple_has_body_p (fndecl))
563 {
391cf42b 564 gcc_assert (chkp_instrumentable_p (fndecl));
565 tree_function_versioning (fndecl, new_decl, NULL, false,
566 NULL, false, NULL, NULL);
567 clone->lowered = true;
058a1b7a 568 }
569
570 /* New params are inserted after versioning because it
571 actually copies args list from the original decl. */
572 chkp_add_bounds_params_to_function (new_decl);
573
f21337ef 574 /* Remember builtin fndecl. */
575 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
576 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
577 {
578 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
579 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
580 clone->decl, false);
581 }
582
058a1b7a 583 /* Clones have the same comdat group as originals. */
584 if (node->same_comdat_group
4811e339 585 || (DECL_ONE_ONLY (node->decl)
586 && !DECL_EXTERNAL (node->decl)))
058a1b7a 587 clone->add_to_same_comdat_group (node);
588
589 if (gimple_has_body_p (fndecl))
590 symtab->call_cgraph_insertion_hooks (clone);
591
592 /* Clone all aliases. */
50f2a18b 593 for (i = 0; node->iterate_direct_aliases (i, ref); i++)
94c42181 594 chkp_maybe_create_clone (ref->referring->decl);
058a1b7a 595
596 /* Clone all thunks. */
597 for (e = node->callers; e; e = e->next_caller)
66124ce7 598 if (e->caller->thunk.thunk_p
ac553c65 599 && !e->caller->thunk.add_pointer_bounds_args
600 && !e->caller->instrumentation_clone)
058a1b7a 601 {
602 struct cgraph_node *thunk
603 = chkp_maybe_create_clone (e->caller->decl);
604 /* Redirect thunk clone edge to the node clone. */
605 thunk->callees->redirect_callee (clone);
606 }
607
608 /* For aliases and thunks we should make sure target is cloned
609 to have proper references and edges. */
610 if (node->thunk.thunk_p)
611 chkp_maybe_create_clone (node->callees->callee->decl);
612 else if (node->alias)
613 {
614 struct cgraph_node *target;
615
616 ref = node->ref_list.first_reference ();
617 if (ref)
94c42181 618 {
619 target = chkp_maybe_create_clone (ref->referred->decl);
620 clone->create_reference (target, IPA_REF_ALIAS);
621 }
058a1b7a 622
623 if (node->alias_target)
624 {
625 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
626 {
627 target = chkp_maybe_create_clone (node->alias_target);
628 clone->alias_target = target->decl;
629 }
630 else
631 clone->alias_target = node->alias_target;
632 }
633 }
634
635 /* Add IPA reference. It's main role is to keep instrumented
636 version reachable while original node is reachable. */
637 ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
638 }
639
640 return clone;
641}
642
643/* Create clone for all functions to be instrumented. */
644
645static unsigned int
646chkp_versioning (void)
647{
648 struct cgraph_node *node;
66124ce7 649 const char *reason;
058a1b7a 650
651 bitmap_obstack_initialize (NULL);
652
653 FOR_EACH_DEFINED_FUNCTION (node)
654 {
37af779a 655 tree decl = node->decl;
058a1b7a 656 if (!node->instrumentation_clone
657 && !node->instrumented_version
658 && !node->alias
659 && !node->thunk.thunk_p
37af779a 660 && (!DECL_BUILT_IN (decl)
661 || (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
662 && DECL_FUNCTION_CODE (decl) < BEGIN_CHKP_BUILTINS)))
66124ce7 663 {
37af779a 664 if (chkp_instrumentable_p (decl))
665 chkp_maybe_create_clone (decl);
666 else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (decl))))
66124ce7 667 {
37af779a 668 if (warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wchkp,
66124ce7 669 "function cannot be instrumented"))
37af779a 670 inform (DECL_SOURCE_LOCATION (decl), reason, decl);
66124ce7 671 }
672 }
058a1b7a 673 }
674
675 /* Mark all aliases and thunks of functions with no instrumented
676 version as legacy function. */
677 FOR_EACH_DEFINED_FUNCTION (node)
678 {
679 if (!node->instrumentation_clone
680 && !node->instrumented_version
681 && (node->alias || node->thunk.thunk_p)
682 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
683 DECL_ATTRIBUTES (node->decl)
684 = tree_cons (get_identifier ("bnd_legacy"), NULL,
685 DECL_ATTRIBUTES (node->decl));
686 }
687
688 bitmap_obstack_release (NULL);
689
690 return 0;
691}
692
693/* In this pass we remove bodies of functions having
694 instrumented version. Functions with removed bodies
695 become a special kind of thunks to provide a connection
696 between calls to the original version and instrumented
697 function. */
698
699static unsigned int
312322ab 700chkp_produce_thunks (bool early)
058a1b7a 701{
702 struct cgraph_node *node;
703
704 FOR_EACH_DEFINED_FUNCTION (node)
705 {
706 if (!node->instrumentation_clone
707 && node->instrumented_version
708 && gimple_has_body_p (node->decl)
312322ab 709 && gimple_has_body_p (node->instrumented_version->decl)
710 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
711 || !early))
058a1b7a 712 {
713 node->release_body ();
714 node->remove_callees ();
715 node->remove_all_references ();
716
717 node->thunk.thunk_p = true;
718 node->thunk.add_pointer_bounds_args = true;
719 node->create_edge (node->instrumented_version, NULL,
db9cef39 720 node->count, CGRAPH_FREQ_BASE);
058a1b7a 721 node->create_reference (node->instrumented_version,
722 IPA_REF_CHKP, NULL);
0c57c0f9 723 /* Thunk shouldn't be a cdtor. */
724 DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
725 DECL_STATIC_DESTRUCTOR (node->decl) = 0;
058a1b7a 726 }
727 }
728
729 /* Mark instrumentation clones created for aliases and thunks
730 as insttrumented so they could be removed as unreachable
731 now. */
312322ab 732 if (!early)
058a1b7a 733 {
312322ab 734 FOR_EACH_DEFINED_FUNCTION (node)
735 {
736 if (node->instrumentation_clone
737 && (node->alias || node->thunk.thunk_p)
738 && !chkp_function_instrumented_p (node->decl))
739 chkp_function_mark_instrumented (node->decl);
740 }
058a1b7a 741 }
742
366970c6 743 return TODO_remove_functions;
058a1b7a 744}
745
746const pass_data pass_data_ipa_chkp_versioning =
747{
748 SIMPLE_IPA_PASS, /* type */
749 "chkp_versioning", /* name */
750 OPTGROUP_NONE, /* optinfo_flags */
751 TV_NONE, /* tv_id */
752 0, /* properties_required */
753 0, /* properties_provided */
754 0, /* properties_destroyed */
755 0, /* todo_flags_start */
756 0 /* todo_flags_finish */
757};
758
312322ab 759const pass_data pass_data_ipa_chkp_early_produce_thunks =
760{
761 SIMPLE_IPA_PASS, /* type */
762 "chkp_ecleanup", /* name */
763 OPTGROUP_NONE, /* optinfo_flags */
764 TV_NONE, /* tv_id */
765 0, /* properties_required */
766 0, /* properties_provided */
767 0, /* properties_destroyed */
768 0, /* todo_flags_start */
769 0 /* todo_flags_finish */
770};
771
058a1b7a 772const pass_data pass_data_ipa_chkp_produce_thunks =
773{
774 SIMPLE_IPA_PASS, /* type */
775 "chkp_cleanup", /* name */
776 OPTGROUP_NONE, /* optinfo_flags */
777 TV_NONE, /* tv_id */
778 0, /* properties_required */
779 0, /* properties_provided */
780 0, /* properties_destroyed */
781 0, /* todo_flags_start */
782 0 /* todo_flags_finish */
783};
784
785class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
786{
787public:
788 pass_ipa_chkp_versioning (gcc::context *ctxt)
789 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
790 {}
791
792 /* opt_pass methods: */
793 virtual opt_pass * clone ()
794 {
795 return new pass_ipa_chkp_versioning (m_ctxt);
796 }
797
798 virtual bool gate (function *)
799 {
800 return flag_check_pointer_bounds;
801 }
802
803 virtual unsigned int execute (function *)
804 {
805 return chkp_versioning ();
806 }
807
808}; // class pass_ipa_chkp_versioning
809
312322ab 810class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
811{
812public:
813 pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
814 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
815 {}
816
817 /* opt_pass methods: */
818 virtual opt_pass * clone ()
819 {
820 return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
821 }
822
823 virtual bool gate (function *)
824 {
825 return flag_check_pointer_bounds;
826 }
827
828 virtual unsigned int execute (function *)
829 {
830 return chkp_produce_thunks (true);
831 }
832
833}; // class pass_chkp_produce_thunks
834
058a1b7a 835class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
836{
837public:
838 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
839 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
840 {}
841
842 /* opt_pass methods: */
843 virtual opt_pass * clone ()
844 {
845 return new pass_ipa_chkp_produce_thunks (m_ctxt);
846 }
847
848 virtual bool gate (function *)
849 {
850 return flag_check_pointer_bounds;
851 }
852
853 virtual unsigned int execute (function *)
854 {
312322ab 855 return chkp_produce_thunks (false);
058a1b7a 856 }
857
858}; // class pass_chkp_produce_thunks
859
860simple_ipa_opt_pass *
861make_pass_ipa_chkp_versioning (gcc::context *ctxt)
862{
863 return new pass_ipa_chkp_versioning (ctxt);
864}
865
312322ab 866simple_ipa_opt_pass *
867make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
868{
869 return new pass_ipa_chkp_early_produce_thunks (ctxt);
870}
871
058a1b7a 872simple_ipa_opt_pass *
873make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
874{
875 return new pass_ipa_chkp_produce_thunks (ctxt);
876}