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