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