1 /* Pointer Bounds Checker IPA passes.
2    Copyright (C) 2014-2016 Free Software Foundation, Inc.
3    Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
4 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11 
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20 
21 #include "config.h"
22 #define INCLUDE_STRING
23 #include "system.h"
24 #include "coretypes.h"
25 #include "backend.h"
26 #include "tree.h"
27 #include "gimple.h"
28 #include "tree-pass.h"
29 #include "stringpool.h"
30 #include "lto-streamer.h"
31 #include "stor-layout.h"
32 #include "calls.h"
33 #include "cgraph.h"
34 #include "tree-chkp.h"
35 #include "tree-inline.h"
36 #include "ipa-chkp.h"
37 
38 /*  Pointer Bounds Checker has two IPA passes to support code instrumentation.
39 
40     In instrumented code each pointer is provided with bounds.  For input
41     pointer parameters it means we also have bounds passed.  For calls it
42     means we have additional bounds arguments for pointer arguments.
43 
44     To have all IPA optimizations working correctly we have to express
45     dataflow between passed and received bounds explicitly via additional
46     entries in function declaration arguments list and in function type.
47     Since we may have both instrumented and not instrumented code at the
48     same time, we cannot replace all original functions with their
49     instrumented variants.  Therefore we create clones (versions) instead.
50 
51     Instrumentation clones creation is a separate IPA pass which is a part
52     of early local passes.  Clones are created after SSA is built (because
53     instrumentation pass works on SSA) and before any transformations
54     which may change pointer flow and therefore lead to incorrect code
55     instrumentation (possibly causing false bounds check failures).
56 
57     Instrumentation clones have pointer bounds arguments added right after
58     pointer arguments.  Clones have assembler name of the original
59     function with suffix added.  New assembler name is in transparent
60     alias chain with the original name.  Thus we expect all calls to the
61     original and instrumented functions look similar in assembler.
62 
63     During instrumentation versioning pass we create instrumented versions
64     of all function with body and also for all their aliases and thunks.
65     Clones for functions with no body are created on demand (usually
66     during call instrumentation).
67 
68     Original and instrumented function nodes are connected with IPA
69     reference IPA_REF_CHKP.  It is mostly done to have reachability
70     analysis working correctly.  We may have no references to the
71     instrumented function in the code but it still should be counted
72     as reachable if the original function is reachable.
73 
74     When original function bodies are not needed anymore we release
75     them and transform functions into a special kind of thunks.  Each
76     thunk has a call edge to the instrumented version.  These thunks
77     help to keep externally visible instrumented functions visible
78     when linker resolution files are used.  Linker has no info about
79     connection between original and instrumented function and
80     therefore we may wrongly decide (due to difference in assembler
81     names) that instrumented function version is local and can be
82     removed.  */
83 
84 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
85 #define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
86 
87 /* Return 1 calls to FNDECL should be replaced with
88    a call to wrapper function.  */
89 bool
chkp_wrap_function(tree fndecl)90 chkp_wrap_function (tree fndecl)
91 {
92   if (!flag_chkp_use_wrappers)
93     return false;
94 
95   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
96     {
97       switch (DECL_FUNCTION_CODE (fndecl))
98 	{
99 	case BUILT_IN_STRLEN:
100 	case BUILT_IN_STRCPY:
101 	case BUILT_IN_STRNCPY:
102 	case BUILT_IN_STPCPY:
103 	case BUILT_IN_STPNCPY:
104 	case BUILT_IN_STRCAT:
105 	case BUILT_IN_STRNCAT:
106 	case BUILT_IN_MEMCPY:
107 	case BUILT_IN_MEMPCPY:
108 	case BUILT_IN_MEMSET:
109 	case BUILT_IN_MEMMOVE:
110 	case BUILT_IN_BZERO:
111 	case BUILT_IN_MALLOC:
112 	case BUILT_IN_CALLOC:
113 	case BUILT_IN_REALLOC:
114 	  return 1;
115 
116 	default:
117 	  return 0;
118 	}
119     }
120 
121   return false;
122 }
123 
124 static const char *
chkp_wrap_function_name(tree fndecl)125 chkp_wrap_function_name (tree fndecl)
126 {
127   gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL);
128 
129   switch (DECL_FUNCTION_CODE (fndecl))
130     {
131     case BUILT_IN_STRLEN:
132       return CHKP_WRAPPER_SYMBOL_PREFIX "strlen";
133     case BUILT_IN_STRCPY:
134       return CHKP_WRAPPER_SYMBOL_PREFIX "strcpy";
135     case BUILT_IN_STRNCPY:
136       return CHKP_WRAPPER_SYMBOL_PREFIX "strncpy";
137     case BUILT_IN_STPCPY:
138       return CHKP_WRAPPER_SYMBOL_PREFIX "stpcpy";
139     case BUILT_IN_STPNCPY:
140       return CHKP_WRAPPER_SYMBOL_PREFIX "stpncpy";
141     case BUILT_IN_STRCAT:
142       return CHKP_WRAPPER_SYMBOL_PREFIX "strcat";
143     case BUILT_IN_STRNCAT:
144       return CHKP_WRAPPER_SYMBOL_PREFIX "strncat";
145     case BUILT_IN_MEMCPY:
146       return CHKP_WRAPPER_SYMBOL_PREFIX "memcpy";
147     case BUILT_IN_MEMPCPY:
148       return CHKP_WRAPPER_SYMBOL_PREFIX "mempcpy";
149     case BUILT_IN_MEMSET:
150       return CHKP_WRAPPER_SYMBOL_PREFIX "memset";
151     case BUILT_IN_MEMMOVE:
152       return CHKP_WRAPPER_SYMBOL_PREFIX "memmove";
153     case BUILT_IN_BZERO:
154       return CHKP_WRAPPER_SYMBOL_PREFIX "bzero";
155     case BUILT_IN_MALLOC:
156       return CHKP_WRAPPER_SYMBOL_PREFIX "malloc";
157     case BUILT_IN_CALLOC:
158       return CHKP_WRAPPER_SYMBOL_PREFIX "calloc";
159     case BUILT_IN_REALLOC:
160       return CHKP_WRAPPER_SYMBOL_PREFIX "realloc";
161 
162     default:
163       gcc_unreachable ();
164     }
165 
166   return "";
167 }
168 
169 /* Build a clone of FNDECL with a modified name.  */
170 
171 static tree
chkp_build_instrumented_fndecl(tree fndecl)172 chkp_build_instrumented_fndecl (tree fndecl)
173 {
174   tree new_decl = copy_node (fndecl);
175   tree new_name;
176   std::string s;
177 
178   /* called_as_built_in checks DECL_NAME to identify calls to
179      builtins.  We want instrumented calls to builtins to be
180      recognized by called_as_built_in.  Therefore use original
181      DECL_NAME for cloning with no prefixes.  */
182   s = IDENTIFIER_POINTER (DECL_NAME (fndecl));
183   s += ".chkp";
184   DECL_NAME (new_decl) = get_identifier (s.c_str ());
185 
186   /* References to the original and to the instrumented version
187      should look the same in the output assembly.  And we cannot
188      use the same assembler name for the instrumented version
189      because it conflicts with decl merging algorithms in LTO.
190      Achieve the result by using transparent alias name for the
191      instrumented version.  */
192   if (chkp_wrap_function(fndecl))
193     {
194       new_name = get_identifier (chkp_wrap_function_name (fndecl));
195       DECL_VISIBILITY (new_decl) = VISIBILITY_DEFAULT;
196     }
197   else
198     {
199       s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
200       s += ".chkp";
201       new_name = get_identifier (s.c_str ());
202       IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
203       TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
204     }
205   SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
206 
207   /* For functions with body versioning will make a copy of arguments.
208      For functions with no body we need to do it here.  */
209   if (!gimple_has_body_p (fndecl))
210     {
211       tree arg;
212 
213       DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
214       for (arg = DECL_ARGUMENTS (new_decl); arg; arg = DECL_CHAIN (arg))
215 	DECL_CONTEXT (arg) = new_decl;
216     }
217 
218   /* We are going to modify attributes list and therefore should
219      make own copy.  */
220   DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
221 
222   /* Change builtin function code.  */
223   if (DECL_BUILT_IN (new_decl))
224     {
225       gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL);
226       gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS);
227       DECL_FUNCTION_CODE (new_decl)
228 	= (enum built_in_function)(DECL_FUNCTION_CODE (new_decl)
229 				   + BEGIN_CHKP_BUILTINS + 1);
230     }
231 
232   return new_decl;
233 }
234 
235 
236 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
237    Integer operands are replaced with values according to
238    INDEXES map having LEN elements.  For operands out of len
239    we just add DELTA.  */
240 
241 static void
chkp_map_attr_arg_indexes(tree attrs,const char * attr_name,unsigned * indexes,int len,int delta)242 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
243 			   unsigned *indexes, int len, int delta)
244 {
245   tree attr = lookup_attribute (attr_name, attrs);
246   tree op;
247 
248   if (!attr)
249     return;
250 
251   TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
252   for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
253     {
254       int idx;
255 
256       if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
257 	continue;
258 
259       idx = TREE_INT_CST_LOW (TREE_VALUE (op));
260 
261       /* If idx exceeds indexes length then we just
262 	 keep it at the same distance from the last
263 	 known arg.  */
264       if (idx > len)
265 	idx += delta;
266       else
267 	idx = indexes[idx - 1] + 1;
268       TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
269     }
270 }
271 
272 /* Make a copy of function type ORIG_TYPE adding pointer
273    bounds as additional arguments.  */
274 
275 tree
chkp_copy_function_type_adding_bounds(tree orig_type)276 chkp_copy_function_type_adding_bounds (tree orig_type)
277 {
278   tree type;
279   tree arg_type, attrs;
280   unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
281   unsigned *indexes = XALLOCAVEC (unsigned, len);
282   unsigned idx = 0, new_idx = 0;
283 
284   for (arg_type = TYPE_ARG_TYPES (orig_type);
285        arg_type;
286        arg_type = TREE_CHAIN (arg_type))
287     if (TREE_VALUE (arg_type) == void_type_node)
288       continue;
289     else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
290 	     || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
291 				   TREE_VALUE (arg_type), true)
292 	     || chkp_type_has_pointer (TREE_VALUE (arg_type)))
293       break;
294 
295   /* We may use original type if there are no bounds passed.  */
296   if (!arg_type)
297     return orig_type;
298 
299   type = build_distinct_type_copy (orig_type);
300   TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
301 
302   for (arg_type = TYPE_ARG_TYPES (type);
303        arg_type;
304        arg_type = TREE_CHAIN (arg_type))
305     {
306       indexes[idx++] = new_idx++;
307 
308       /* pass_by_reference returns 1 for void type,
309 	 so check for it first.  */
310       if (TREE_VALUE (arg_type) == void_type_node)
311 	continue;
312       else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
313 	       || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
314 				     TREE_VALUE (arg_type), true))
315 	{
316 	  tree new_type = build_tree_list (NULL_TREE,
317 					   pointer_bounds_type_node);
318 	  TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
319 	  TREE_CHAIN (arg_type) = new_type;
320 
321 	  arg_type = TREE_CHAIN (arg_type);
322 	  new_idx++;
323 	}
324       else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
325 	{
326 	  bitmap slots = BITMAP_ALLOC (NULL);
327 	  bitmap_iterator bi;
328 	  unsigned bnd_no;
329 
330 	  chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
331 
332 	  EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
333 	    {
334 	      tree new_type = build_tree_list (NULL_TREE,
335 					       pointer_bounds_type_node);
336 	      TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
337 	      TREE_CHAIN (arg_type) = new_type;
338 
339 	      arg_type = TREE_CHAIN (arg_type);
340 	      new_idx++;
341 	    }
342 	  BITMAP_FREE (slots);
343 	}
344     }
345 
346   /* If function type has attribute with arg indexes then
347      we have to copy it fixing attribute ops.  Map for
348      fixing is in indexes array.  */
349   attrs = TYPE_ATTRIBUTES (type);
350   if (lookup_attribute ("nonnull", attrs)
351       || lookup_attribute ("format", attrs)
352       || lookup_attribute ("format_arg", attrs))
353     {
354       int delta = new_idx - len;
355       attrs = copy_list (TYPE_ATTRIBUTES (type));
356       chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
357       chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
358       chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
359       TYPE_ATTRIBUTES (type) = attrs;
360     }
361 
362   return type;
363 }
364 
365 /* For given function FNDECL add bounds arguments to arguments
366    list.  */
367 
368 static void
chkp_add_bounds_params_to_function(tree fndecl)369 chkp_add_bounds_params_to_function (tree fndecl)
370 {
371   tree arg;
372 
373   for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
374     if (BOUNDED_P (arg))
375       {
376 	std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
377 	tree new_arg;
378 
379 	if (DECL_NAME (arg))
380 	  new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
381 	else
382 	  {
383 	    char uid[25];
384 	    snprintf (uid, 25, "D.%u", DECL_UID (arg));
385 	    new_name += uid;
386 	  }
387 
388 	new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
389 			      get_identifier (new_name.c_str ()),
390 			      pointer_bounds_type_node);
391 	DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
392 	DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
393 	DECL_ARTIFICIAL (new_arg) = 1;
394 	DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
395 	DECL_CHAIN (arg) = new_arg;
396 
397 	arg = DECL_CHAIN (arg);
398 
399       }
400     else if (chkp_type_has_pointer (TREE_TYPE (arg)))
401       {
402 	tree orig_arg = arg;
403 	bitmap slots = BITMAP_ALLOC (NULL);
404 	bitmap_iterator bi;
405 	unsigned bnd_no;
406 
407 	chkp_find_bound_slots (TREE_TYPE (arg), slots);
408 
409 	EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
410 	  {
411 	    std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
412 	    tree new_arg;
413 	    char offs[25];
414 
415 	    if (DECL_NAME (orig_arg))
416 	      new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
417 	    else
418 	      {
419 		snprintf (offs, 25, "D.%u", DECL_UID (arg));
420 		new_name += offs;
421 	      }
422 	    snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
423 
424 	    new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
425 				  PARM_DECL,
426 				  get_identifier (new_name.c_str ()),
427 				  pointer_bounds_type_node);
428 	    DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
429 	    DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
430 	    DECL_ARTIFICIAL (new_arg) = 1;
431 	    DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
432 	    DECL_CHAIN (arg) = new_arg;
433 
434 	    arg = DECL_CHAIN (arg);
435 	  }
436 	BITMAP_FREE (slots);
437       }
438 
439   TREE_TYPE (fndecl) =
440     chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
441 }
442 
443 /* Return an instrumentation clone for builtin function
444    FNDECL.  Create one if needed.  */
445 
446 tree
chkp_maybe_clone_builtin_fndecl(tree fndecl)447 chkp_maybe_clone_builtin_fndecl (tree fndecl)
448 {
449   tree clone;
450   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
451 
452   gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
453 	      && fcode < BEGIN_CHKP_BUILTINS);
454 
455   fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
456   clone = builtin_decl_explicit (fcode);
457   if (clone)
458     return clone;
459 
460   clone = chkp_build_instrumented_fndecl (fndecl);
461   chkp_add_bounds_params_to_function (clone);
462 
463   gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
464 
465   set_builtin_decl (fcode, clone, false);
466 
467   return clone;
468 }
469 
470 /* Return 1 if function FNDECL should be instrumented.  */
471 
472 bool
chkp_instrumentable_p(tree fndecl)473 chkp_instrumentable_p (tree fndecl)
474 {
475   struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
476   return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
477 	  && (!flag_chkp_instrument_marked_only
478 	      || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl)))
479 	  && (!fn || !copy_forbidden (fn)));
480 }
481 
482 /* Return clone created for instrumentation of NODE or NULL.  */
483 
484 cgraph_node *
chkp_maybe_create_clone(tree fndecl)485 chkp_maybe_create_clone (tree fndecl)
486 {
487   cgraph_node *node = cgraph_node::get_create (fndecl);
488   cgraph_node *clone = node->instrumented_version;
489 
490   gcc_assert (!node->instrumentation_clone);
491 
492   if (DECL_BUILT_IN (fndecl)
493       && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
494 	  || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
495     return NULL;
496 
497   clone = node->instrumented_version;
498 
499   /* Some instrumented builtin function calls may be optimized and
500      cgraph nodes may be removed as unreachable.  Later optimizations
501      may generate new calls to removed functions and in this case
502      we have to recreate cgraph node.  FUNCTION_DECL for instrumented
503      builtin still exists and should be reused in such case.  */
504   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
505       && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))
506       && !clone)
507     {
508       enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
509       tree new_decl;
510 
511       fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
512       new_decl = builtin_decl_explicit (fncode);
513 
514       /* We've actually already created an instrumented clone once.
515 	 Restore it.  */
516       if (new_decl)
517 	{
518 	  clone = cgraph_node::get (new_decl);
519 
520 	  if (!clone)
521 	    {
522 	      gcc_assert (!gimple_has_body_p (fndecl));
523 	      clone = cgraph_node::get_create (new_decl);
524 	      clone->externally_visible = node->externally_visible;
525 	      clone->local = node->local;
526 	      clone->address_taken = node->address_taken;
527 	      clone->thunk = node->thunk;
528 	      clone->alias = node->alias;
529 	      clone->weakref = node->weakref;
530 	      clone->cpp_implicit_alias = node->cpp_implicit_alias;
531 	      clone->orig_decl = fndecl;
532 	      clone->instrumentation_clone = true;
533 	    }
534 
535 	  clone->instrumented_version = node;
536 	  node->instrumented_version = clone;
537 	}
538     }
539 
540   if (!clone)
541     {
542       tree new_decl = chkp_build_instrumented_fndecl (fndecl);
543       struct cgraph_edge *e;
544       struct ipa_ref *ref;
545       int i;
546 
547       clone = node->create_version_clone (new_decl, vNULL, NULL);
548       clone->externally_visible = node->externally_visible;
549       clone->local = node->local;
550       clone->address_taken = node->address_taken;
551       clone->thunk = node->thunk;
552       clone->alias = node->alias;
553       clone->weakref = node->weakref;
554       clone->cpp_implicit_alias = node->cpp_implicit_alias;
555       clone->instrumented_version = node;
556       clone->orig_decl = fndecl;
557       clone->instrumentation_clone = true;
558       node->instrumented_version = clone;
559 
560       if (gimple_has_body_p (fndecl))
561 	{
562 	  gcc_assert (chkp_instrumentable_p (fndecl));
563 	  tree_function_versioning (fndecl, new_decl, NULL, false,
564 				    NULL, false, NULL, NULL);
565 	  clone->lowered = true;
566 	}
567 
568       /* New params are inserted after versioning because it
569 	 actually copies args list from the original decl.  */
570       chkp_add_bounds_params_to_function (new_decl);
571 
572       /* Remember builtin fndecl.  */
573       if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
574 	  && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
575 	{
576 	  gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
577 	  set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
578 			    clone->decl, false);
579 	}
580 
581       /* Clones have the same comdat group as originals.  */
582       if (node->same_comdat_group
583 	  || (DECL_ONE_ONLY (node->decl)
584 	      && !DECL_EXTERNAL (node->decl)))
585 	clone->add_to_same_comdat_group (node);
586 
587       if (gimple_has_body_p (fndecl))
588 	symtab->call_cgraph_insertion_hooks (clone);
589 
590       /* Clone all aliases.  */
591       for (i = 0; node->iterate_direct_aliases (i, ref); i++)
592 	chkp_maybe_create_clone (ref->referring->decl);
593 
594       /* Clone all thunks.  */
595       for (e = node->callers; e; e = e->next_caller)
596 	if (e->caller->thunk.thunk_p
597 	    && !e->caller->thunk.add_pointer_bounds_args
598 	    && !e->caller->instrumentation_clone)
599 	  {
600 	    struct cgraph_node *thunk
601 	      = chkp_maybe_create_clone (e->caller->decl);
602 	    /* Redirect thunk clone edge to the node clone.  */
603 	    thunk->callees->redirect_callee (clone);
604 	  }
605 
606       /* For aliases and thunks we should make sure target is cloned
607 	 to have proper references and edges.  */
608       if (node->thunk.thunk_p)
609 	chkp_maybe_create_clone (node->callees->callee->decl);
610       else if (node->alias)
611 	{
612 	  struct cgraph_node *target;
613 
614 	  ref = node->ref_list.first_reference ();
615 	  if (ref)
616 	    {
617 	      target = chkp_maybe_create_clone (ref->referred->decl);
618 	      clone->create_reference (target, IPA_REF_ALIAS);
619 	    }
620 
621 	  if (node->alias_target)
622 	    {
623 	      if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
624 		{
625 		  target = chkp_maybe_create_clone (node->alias_target);
626 		  clone->alias_target = target->decl;
627 		}
628 	      else
629 		clone->alias_target = node->alias_target;
630 	    }
631 	}
632 
633       /* Add IPA reference.  It's main role is to keep instrumented
634 	 version reachable while original node is reachable.  */
635       ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
636     }
637 
638   return clone;
639 }
640 
641 /* Create clone for all functions to be instrumented.  */
642 
643 static unsigned int
chkp_versioning(void)644 chkp_versioning (void)
645 {
646   struct cgraph_node *node;
647   const char *reason;
648 
649   bitmap_obstack_initialize (NULL);
650 
651   FOR_EACH_DEFINED_FUNCTION (node)
652     {
653       tree decl = node->decl;
654       if (!node->instrumentation_clone
655 	  && !node->instrumented_version
656 	  && !node->alias
657 	  && !node->thunk.thunk_p
658 	  && (!DECL_BUILT_IN (decl)
659 	      || (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
660 		  && DECL_FUNCTION_CODE (decl) < BEGIN_CHKP_BUILTINS)))
661 	{
662 	  if (chkp_instrumentable_p (decl))
663 	    chkp_maybe_create_clone (decl);
664 	  else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (decl))))
665 	    {
666 	      if (warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wchkp,
667 			      "function cannot be instrumented"))
668 		inform (DECL_SOURCE_LOCATION (decl), reason, decl);
669 	    }
670 	}
671     }
672 
673   /* Mark all aliases and thunks of functions with no instrumented
674      version as legacy function.  */
675   FOR_EACH_DEFINED_FUNCTION (node)
676     {
677       if (!node->instrumentation_clone
678 	  && !node->instrumented_version
679 	  && (node->alias || node->thunk.thunk_p)
680 	  && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
681 	DECL_ATTRIBUTES (node->decl)
682 	  = tree_cons (get_identifier ("bnd_legacy"), NULL,
683 		       DECL_ATTRIBUTES (node->decl));
684     }
685 
686   bitmap_obstack_release (NULL);
687 
688   return 0;
689 }
690 
691 /* In this pass we remove bodies of functions having
692    instrumented version.  Functions with removed bodies
693    become a special kind of thunks to provide a connection
694    between calls to the original version and instrumented
695    function.  */
696 
697 static unsigned int
chkp_produce_thunks(bool early)698 chkp_produce_thunks (bool early)
699 {
700   struct cgraph_node *node;
701 
702   FOR_EACH_DEFINED_FUNCTION (node)
703     {
704       if (!node->instrumentation_clone
705 	  && node->instrumented_version
706 	  && gimple_has_body_p (node->decl)
707 	  && gimple_has_body_p (node->instrumented_version->decl)
708 	  && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
709 	      || !early))
710 	{
711 	  node->release_body ();
712 	  node->remove_callees ();
713 	  node->remove_all_references ();
714 
715 	  node->thunk.thunk_p = true;
716 	  node->thunk.add_pointer_bounds_args = true;
717 	  node->create_edge (node->instrumented_version, NULL,
718 			     0, CGRAPH_FREQ_BASE);
719 	  node->create_reference (node->instrumented_version,
720 			       IPA_REF_CHKP, NULL);
721 	  /* Thunk shouldn't be a cdtor.  */
722 	  DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
723 	  DECL_STATIC_DESTRUCTOR (node->decl) = 0;
724 	}
725     }
726 
727   /* Mark instrumentation clones created for aliases and thunks
728      as insttrumented so they could be removed as unreachable
729      now.  */
730   if (!early)
731     {
732       FOR_EACH_DEFINED_FUNCTION (node)
733       {
734 	if (node->instrumentation_clone
735 	    && (node->alias || node->thunk.thunk_p)
736 	    && !chkp_function_instrumented_p (node->decl))
737 	  chkp_function_mark_instrumented (node->decl);
738       }
739     }
740 
741   return TODO_remove_functions;
742 }
743 
744 const pass_data pass_data_ipa_chkp_versioning =
745 {
746   SIMPLE_IPA_PASS, /* type */
747   "chkp_versioning", /* name */
748   OPTGROUP_NONE, /* optinfo_flags */
749   TV_NONE, /* tv_id */
750   0, /* properties_required */
751   0, /* properties_provided */
752   0, /* properties_destroyed */
753   0, /* todo_flags_start */
754   0 /* todo_flags_finish */
755 };
756 
757 const pass_data pass_data_ipa_chkp_early_produce_thunks =
758 {
759   SIMPLE_IPA_PASS, /* type */
760   "chkp_ecleanup", /* name */
761   OPTGROUP_NONE, /* optinfo_flags */
762   TV_NONE, /* tv_id */
763   0, /* properties_required */
764   0, /* properties_provided */
765   0, /* properties_destroyed */
766   0, /* todo_flags_start */
767   0 /* todo_flags_finish */
768 };
769 
770 const pass_data pass_data_ipa_chkp_produce_thunks =
771 {
772   SIMPLE_IPA_PASS, /* type */
773   "chkp_cleanup", /* name */
774   OPTGROUP_NONE, /* optinfo_flags */
775   TV_NONE, /* tv_id */
776   0, /* properties_required */
777   0, /* properties_provided */
778   0, /* properties_destroyed */
779   0, /* todo_flags_start */
780   0 /* todo_flags_finish */
781 };
782 
783 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
784 {
785 public:
pass_ipa_chkp_versioning(gcc::context * ctxt)786   pass_ipa_chkp_versioning (gcc::context *ctxt)
787     : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
788   {}
789 
790   /* opt_pass methods: */
clone()791   virtual opt_pass * clone ()
792     {
793       return new pass_ipa_chkp_versioning (m_ctxt);
794     }
795 
gate(function *)796   virtual bool gate (function *)
797     {
798       return flag_check_pointer_bounds;
799     }
800 
execute(function *)801   virtual unsigned int execute (function *)
802     {
803       return chkp_versioning ();
804     }
805 
806 }; // class pass_ipa_chkp_versioning
807 
808 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
809 {
810 public:
pass_ipa_chkp_early_produce_thunks(gcc::context * ctxt)811   pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
812     : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
813   {}
814 
815   /* opt_pass methods: */
clone()816   virtual opt_pass * clone ()
817     {
818       return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
819     }
820 
gate(function *)821   virtual bool gate (function *)
822     {
823       return flag_check_pointer_bounds;
824     }
825 
execute(function *)826   virtual unsigned int execute (function *)
827     {
828       return chkp_produce_thunks (true);
829     }
830 
831 }; // class pass_chkp_produce_thunks
832 
833 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
834 {
835 public:
pass_ipa_chkp_produce_thunks(gcc::context * ctxt)836   pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
837     : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
838   {}
839 
840   /* opt_pass methods: */
clone()841   virtual opt_pass * clone ()
842     {
843       return new pass_ipa_chkp_produce_thunks (m_ctxt);
844     }
845 
gate(function *)846   virtual bool gate (function *)
847     {
848       return flag_check_pointer_bounds;
849     }
850 
execute(function *)851   virtual unsigned int execute (function *)
852     {
853       return chkp_produce_thunks (false);
854     }
855 
856 }; // class pass_chkp_produce_thunks
857 
858 simple_ipa_opt_pass *
make_pass_ipa_chkp_versioning(gcc::context * ctxt)859 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
860 {
861   return new pass_ipa_chkp_versioning (ctxt);
862 }
863 
864 simple_ipa_opt_pass *
make_pass_ipa_chkp_early_produce_thunks(gcc::context * ctxt)865 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
866 {
867   return new pass_ipa_chkp_early_produce_thunks (ctxt);
868 }
869 
870 simple_ipa_opt_pass *
make_pass_ipa_chkp_produce_thunks(gcc::context * ctxt)871 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
872 {
873   return new pass_ipa_chkp_produce_thunks (ctxt);
874 }
875