Import GCC-8 to a new vendor branch
[dragonfly.git] / contrib / gcc-8.0 / gcc / ipa-chkp.c
1 /* Pointer Bounds Checker IPA passes.
2    Copyright (C) 2014-2018 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 #include "stringpool.h"
38 #include "attribs.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     {
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     }
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
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
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
243 static void
244 chkp_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
277 tree
278 chkp_copy_function_type_adding_bounds (tree orig_type)
279 {
280   tree type;
281   tree arg_type, attrs;
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
301   type = build_distinct_type_copy (orig_type);
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
364   return type;
365 }
366
367 /* For given function FNDECL add bounds arguments to arguments
368    list.  */
369
370 static void
371 chkp_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
445 /* Return an instrumentation clone for builtin function
446    FNDECL.  Create one if needed.  */
447
448 tree
449 chkp_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
472 /* Return 1 if function FNDECL should be instrumented.  */
473
474 bool
475 chkp_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)))
481           && (!fn || !copy_forbidden (fn)));
482 }
483
484 /* Return clone created for instrumentation of NODE or NULL.  */
485
486 cgraph_node *
487 chkp_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
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
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         {
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;
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
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
583       /* Clones have the same comdat group as originals.  */
584       if (node->same_comdat_group
585           || (DECL_ONE_ONLY (node->decl)
586               && !DECL_EXTERNAL (node->decl)))
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.  */
593       for (i = 0; node->iterate_direct_aliases (i, ref); i++)
594         chkp_maybe_create_clone (ref->referring->decl);
595
596       /* Clone all thunks.  */
597       for (e = node->callers; e; e = e->next_caller)
598         if (e->caller->thunk.thunk_p
599             && !e->caller->thunk.add_pointer_bounds_args
600             && !e->caller->instrumentation_clone)
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)
618             {
619               target = chkp_maybe_create_clone (ref->referred->decl);
620               clone->create_reference (target, IPA_REF_ALIAS);
621             }
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
645 static unsigned int
646 chkp_versioning (void)
647 {
648   struct cgraph_node *node;
649   const char *reason;
650
651   bitmap_obstack_initialize (NULL);
652
653   FOR_EACH_DEFINED_FUNCTION (node)
654     {
655       tree decl = node->decl;
656       if (!node->instrumentation_clone
657           && !node->instrumented_version
658           && !node->alias
659           && !node->thunk.thunk_p
660           && (!DECL_BUILT_IN (decl)
661               || (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
662                   && DECL_FUNCTION_CODE (decl) < BEGIN_CHKP_BUILTINS)))
663         {
664           if (chkp_instrumentable_p (decl))
665             chkp_maybe_create_clone (decl);
666           else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (decl))))
667             {
668               if (warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wchkp,
669                               "function cannot be instrumented"))
670                 inform (DECL_SOURCE_LOCATION (decl), reason, decl);
671             }
672         }
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
699 static unsigned int
700 chkp_produce_thunks (bool early)
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)
709           && gimple_has_body_p (node->instrumented_version->decl)
710           && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
711               || !early))
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,
720                              node->count);
721           node->create_reference (node->instrumented_version,
722                                IPA_REF_CHKP, NULL);
723           /* Thunk shouldn't be a cdtor.  */
724           DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
725           DECL_STATIC_DESTRUCTOR (node->decl) = 0;
726         }
727     }
728
729   /* Mark instrumentation clones created for aliases and thunks
730      as insttrumented so they could be removed as unreachable
731      now.  */
732   if (!early)
733     {
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       }
741     }
742
743   return TODO_remove_functions;
744 }
745
746 const 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
759 const 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
772 const 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
785 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
786 {
787 public:
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
810 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
811 {
812 public:
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
835 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
836 {
837 public:
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     {
855       return chkp_produce_thunks (false);
856     }
857
858 }; // class pass_chkp_produce_thunks
859
860 simple_ipa_opt_pass *
861 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
862 {
863   return new pass_ipa_chkp_versioning (ctxt);
864 }
865
866 simple_ipa_opt_pass *
867 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
868 {
869   return new pass_ipa_chkp_early_produce_thunks (ctxt);
870 }
871
872 simple_ipa_opt_pass *
873 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
874 {
875   return new pass_ipa_chkp_produce_thunks (ctxt);
876 }