alias.c: Reorder #include statements and remove duplicates.
[platform/upstream/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 "backend.h"
25 #include "hard-reg-set.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 "alias.h"
32 #include "fold-const.h"
33 #include "stor-layout.h"
34 #include "calls.h"
35 #include "cgraph.h"
36 #include "tree-chkp.h"
37 #include "tree-inline.h"
38 #include "ipa-chkp.h"
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_"
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.  */
91 bool
92 chkp_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 }
125
126 static const char *
127 chkp_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
171 /* Build a clone of FNDECL with a modified name.  */
172
173 static tree
174 chkp_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.  */
194   if (chkp_wrap_function(fndecl))
195     {
196       new_name = get_identifier (chkp_wrap_function_name (fndecl));
197       DECL_VISIBILITY (new_decl) = VISIBILITY_DEFAULT;
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     }
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
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
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
237 static void
238 chkp_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
271 tree
272 chkp_copy_function_type_adding_bounds (tree orig_type)
273 {
274   tree type;
275   tree arg_type, attrs;
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
295   type = build_distinct_type_copy (orig_type);
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
358   return type;
359 }
360
361 /* For given function FNDECL add bounds arguments to arguments
362    list.  */
363
364 static void
365 chkp_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
439 /* Return an instrumentation clone for builtin function
440    FNDECL.  Create one if needed.  */
441
442 tree
443 chkp_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
466 /* Return 1 if function FNDECL should be instrumented.  */
467
468 bool
469 chkp_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
478 /* Return clone created for instrumentation of NODE or NULL.  */
479
480 cgraph_node *
481 chkp_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
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
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         {
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;
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
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
577       /* Clones have the same comdat group as originals.  */
578       if (node->same_comdat_group
579           || (DECL_ONE_ONLY (node->decl)
580               && !DECL_EXTERNAL (node->decl)))
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.  */
587       for (i = 0; node->iterate_direct_aliases (i, ref); i++)
588         chkp_maybe_create_clone (ref->referring->decl);
589
590       /* Clone all thunks.  */
591       for (e = node->callers; e; e = e->next_caller)
592         if (e->caller->thunk.thunk_p
593             && !e->caller->thunk.add_pointer_bounds_args
594             && !e->caller->instrumentation_clone)
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)
612             {
613               target = chkp_maybe_create_clone (ref->referred->decl);
614               clone->create_reference (target, IPA_REF_ALIAS);
615             }
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
639 static unsigned int
640 chkp_versioning (void)
641 {
642   struct cgraph_node *node;
643   const char *reason;
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
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)))
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         }
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
693 static unsigned int
694 chkp_produce_thunks (bool early)
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)
703           && gimple_has_body_p (node->instrumented_version->decl)
704           && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
705               || !early))
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);
717           /* Thunk shouldn't be a cdtor.  */
718           DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
719           DECL_STATIC_DESTRUCTOR (node->decl) = 0;
720         }
721     }
722
723   /* Mark instrumentation clones created for aliases and thunks
724      as insttrumented so they could be removed as unreachable
725      now.  */
726   if (!early)
727     {
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       }
735     }
736
737   return TODO_remove_functions;
738 }
739
740 const 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
753 const 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
766 const 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
779 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
780 {
781 public:
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
804 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
805 {
806 public:
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
829 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
830 {
831 public:
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     {
849       return chkp_produce_thunks (false);
850     }
851
852 }; // class pass_chkp_produce_thunks
853
854 simple_ipa_opt_pass *
855 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
856 {
857   return new pass_ipa_chkp_versioning (ctxt);
858 }
859
860 simple_ipa_opt_pass *
861 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
862 {
863   return new pass_ipa_chkp_early_produce_thunks (ctxt);
864 }
865
866 simple_ipa_opt_pass *
867 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
868 {
869   return new pass_ipa_chkp_produce_thunks (ctxt);
870 }