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