xref: /dragonfly/contrib/gcc-8.0/gcc/ipa-chkp.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
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
chkp_wrap_function(tree fndecl)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 *
chkp_wrap_function_name(tree fndecl)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
chkp_build_instrumented_fndecl(tree fndecl)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
chkp_map_attr_arg_indexes(tree attrs,const char * attr_name,unsigned * indexes,int len,int delta)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
chkp_copy_function_type_adding_bounds(tree orig_type)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
chkp_add_bounds_params_to_function(tree fndecl)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
chkp_maybe_clone_builtin_fndecl(tree fndecl)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
chkp_instrumentable_p(tree fndecl)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 *
chkp_maybe_create_clone(tree fndecl)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
chkp_versioning(void)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
chkp_produce_thunks(bool early)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:
pass_ipa_chkp_versioning(gcc::context * ctxt)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: */
clone()793   virtual opt_pass * clone ()
794     {
795       return new pass_ipa_chkp_versioning (m_ctxt);
796     }
797 
gate(function *)798   virtual bool gate (function *)
799     {
800       return flag_check_pointer_bounds;
801     }
802 
execute(function *)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:
pass_ipa_chkp_early_produce_thunks(gcc::context * ctxt)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: */
clone()818   virtual opt_pass * clone ()
819     {
820       return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
821     }
822 
gate(function *)823   virtual bool gate (function *)
824     {
825       return flag_check_pointer_bounds;
826     }
827 
execute(function *)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:
pass_ipa_chkp_produce_thunks(gcc::context * ctxt)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: */
clone()843   virtual opt_pass * clone ()
844     {
845       return new pass_ipa_chkp_produce_thunks (m_ctxt);
846     }
847 
gate(function *)848   virtual bool gate (function *)
849     {
850       return flag_check_pointer_bounds;
851     }
852 
execute(function *)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 *
make_pass_ipa_chkp_versioning(gcc::context * ctxt)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 *
make_pass_ipa_chkp_early_produce_thunks(gcc::context * ctxt)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 *
make_pass_ipa_chkp_produce_thunks(gcc::context * ctxt)873 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
874 {
875   return new pass_ipa_chkp_produce_thunks (ctxt);
876 }
877