re PR bootstrap/63699 (Bootstrap fails in libcc1 on darwin14)
[gcc.git] / gcc / ipa-chkp.c
1 /* Pointer Bounds Checker IPA passes.
2 Copyright (C) 2014 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 #include "system.h"
23 #include "coretypes.h"
24 #include "tree-core.h"
25 #include "stor-layout.h"
26 #include "tree.h"
27 #include "tree-pass.h"
28 #include "stringpool.h"
29 #include "bitmap.h"
30 #include "gimple-expr.h"
31 #include "tm.h"
32 #include "hard-reg-set.h"
33 #include "function.h"
34 #include "is-a.h"
35 #include "tree-ssa-alias.h"
36 #include "predict.h"
37 #include "basic-block.h"
38 #include "gimple.h"
39 #include "ipa-ref.h"
40 #include "lto-streamer.h"
41 #include "cgraph.h"
42 #include "tree-chkp.h"
43 #include "ipa-chkp.h"
44
45 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
46
47 In instrumented code each pointer is provided with bounds. For input
48 pointer parameters it means we also have bounds passed. For calls it
49 means we have additional bounds arguments for pointer arguments.
50
51 To have all IPA optimizations working correctly we have to express
52 dataflow between passed and received bounds explicitly via additional
53 entries in function declaration arguments list and in function type.
54 Since we may have both instrumented and not instrumented code at the
55 same time, we cannot replace all original functions with their
56 instrumented variants. Therefore we create clones (versions) instead.
57
58 Instrumentation clones creation is a separate IPA pass which is a part
59 of early local passes. Clones are created after SSA is built (because
60 instrumentation pass works on SSA) and before any transformations
61 which may change pointer flow and therefore lead to incorrect code
62 instrumentation (possibly causing false bounds check failures).
63
64 Instrumentation clones have pointer bounds arguments added right after
65 pointer arguments. Clones have assembler name of the original
66 function with suffix added. New assembler name is in transparent
67 alias chain with the original name. Thus we expect all calls to the
68 original and instrumented functions look similar in assembler.
69
70 During instrumentation versioning pass we create instrumented versions
71 of all function with body and also for all their aliases and thunks.
72 Clones for functions with no body are created on demand (usually
73 during call instrumentation).
74
75 Original and instrumented function nodes are connected with IPA
76 reference IPA_REF_CHKP. It is mostly done to have reachability
77 analysis working correctly. We may have no references to the
78 instrumented function in the code but it still should be counted
79 as reachable if the original function is reachable.
80
81 When original function bodies are not needed anymore we release
82 them and transform functions into a special kind of thunks. Each
83 thunk has a call edge to the instrumented version. These thunks
84 help to keep externally visible instrumented functions visible
85 when linker resolution files are used. Linker has no info about
86 connection between original and instrumented function and
87 therefore we may wrongly decide (due to difference in assembler
88 names) that instrumented function version is local and can be
89 removed. */
90
91 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
92
93 /* Build a clone of FNDECL with a modified name. */
94
95 static tree
96 chkp_build_instrumented_fndecl (tree fndecl)
97 {
98 tree new_decl = copy_node (fndecl);
99 tree new_name;
100 std::string s;
101
102 /* called_as_built_in checks DECL_NAME to identify calls to
103 builtins. We want instrumented calls to builtins to be
104 recognized by called_as_built_in. Therefore use original
105 DECL_NAME for cloning with no prefixes. */
106 s = IDENTIFIER_POINTER (DECL_NAME (fndecl));
107 s += ".chkp";
108 DECL_NAME (new_decl) = get_identifier (s.c_str ());
109
110 /* References to the original and to the instrumented version
111 should look the same in the output assembly. And we cannot
112 use the same assembler name for the instrumented version
113 because it conflicts with decl merging algorithms in LTO.
114 Achieve the result by using transparent alias name for the
115 instrumented version. */
116 s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
117 s += ".chkp";
118 new_name = get_identifier (s.c_str ());
119 IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
120 TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
121 SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
122
123 /* For functions with body versioning will make a copy of arguments.
124 For functions with no body we need to do it here. */
125 if (!gimple_has_body_p (fndecl))
126 DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
127
128 /* We are going to modify attributes list and therefore should
129 make own copy. */
130 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
131
132 return new_decl;
133 }
134
135
136 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
137 Integer operands are replaced with values according to
138 INDEXES map having LEN elements. For operands out of len
139 we just add DELTA. */
140
141 static void
142 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
143 unsigned *indexes, int len, int delta)
144 {
145 tree attr = lookup_attribute (attr_name, attrs);
146 tree op;
147
148 if (!attr)
149 return;
150
151 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
152 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
153 {
154 int idx;
155
156 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
157 continue;
158
159 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
160
161 /* If idx exceeds indexes length then we just
162 keep it at the same distance from the last
163 known arg. */
164 if (idx > len)
165 idx += delta;
166 else
167 idx = indexes[idx - 1] + 1;
168 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
169 }
170 }
171
172 /* Make a copy of function type ORIG_TYPE adding pointer
173 bounds as additional arguments. */
174
175 tree
176 chkp_copy_function_type_adding_bounds (tree orig_type)
177 {
178 tree type;
179 tree arg_type, attrs, t;
180 unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
181 unsigned *indexes = XALLOCAVEC (unsigned, len);
182 unsigned idx = 0, new_idx = 0;
183
184 for (arg_type = TYPE_ARG_TYPES (orig_type);
185 arg_type;
186 arg_type = TREE_CHAIN (arg_type))
187 if (TREE_VALUE (arg_type) == void_type_node)
188 continue;
189 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
190 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
191 TREE_VALUE (arg_type), true)
192 || chkp_type_has_pointer (TREE_VALUE (arg_type)))
193 break;
194
195 /* We may use original type if there are no bounds passed. */
196 if (!arg_type)
197 return orig_type;
198
199 type = copy_node (orig_type);
200 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
201
202 for (arg_type = TYPE_ARG_TYPES (type);
203 arg_type;
204 arg_type = TREE_CHAIN (arg_type))
205 {
206 indexes[idx++] = new_idx++;
207
208 /* pass_by_reference returns 1 for void type,
209 so check for it first. */
210 if (TREE_VALUE (arg_type) == void_type_node)
211 continue;
212 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
213 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
214 TREE_VALUE (arg_type), true))
215 {
216 tree new_type = build_tree_list (NULL_TREE,
217 pointer_bounds_type_node);
218 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
219 TREE_CHAIN (arg_type) = new_type;
220
221 arg_type = TREE_CHAIN (arg_type);
222 new_idx++;
223 }
224 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
225 {
226 bitmap slots = BITMAP_ALLOC (NULL);
227 bitmap_iterator bi;
228 unsigned bnd_no;
229
230 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
231
232 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
233 {
234 tree new_type = build_tree_list (NULL_TREE,
235 pointer_bounds_type_node);
236 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
237 TREE_CHAIN (arg_type) = new_type;
238
239 arg_type = TREE_CHAIN (arg_type);
240 new_idx++;
241 }
242 BITMAP_FREE (slots);
243 }
244 }
245
246 /* If function type has attribute with arg indexes then
247 we have to copy it fixing attribute ops. Map for
248 fixing is in indexes array. */
249 attrs = TYPE_ATTRIBUTES (type);
250 if (lookup_attribute ("nonnull", attrs)
251 || lookup_attribute ("format", attrs)
252 || lookup_attribute ("format_arg", attrs))
253 {
254 int delta = new_idx - len;
255 attrs = copy_list (TYPE_ATTRIBUTES (type));
256 chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
257 chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
258 chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
259 TYPE_ATTRIBUTES (type) = attrs;
260 }
261
262 t = TYPE_MAIN_VARIANT (orig_type);
263 if (orig_type != t)
264 {
265 TYPE_MAIN_VARIANT (type) = t;
266 TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (t);
267 TYPE_NEXT_VARIANT (t) = type;
268 }
269 else
270 {
271 TYPE_MAIN_VARIANT (type) = type;
272 TYPE_NEXT_VARIANT (type) = NULL;
273 }
274
275
276 return type;
277 }
278
279 /* For given function FNDECL add bounds arguments to arguments
280 list. */
281
282 static void
283 chkp_add_bounds_params_to_function (tree fndecl)
284 {
285 tree arg;
286
287 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
288 if (BOUNDED_P (arg))
289 {
290 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
291 tree new_arg;
292
293 if (DECL_NAME (arg))
294 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
295 else
296 {
297 char uid[25];
298 snprintf (uid, 25, "D.%u", DECL_UID (arg));
299 new_name += uid;
300 }
301
302 new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
303 get_identifier (new_name.c_str ()),
304 pointer_bounds_type_node);
305 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
306 DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
307 DECL_ARTIFICIAL (new_arg) = 1;
308 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
309 DECL_CHAIN (arg) = new_arg;
310
311 arg = DECL_CHAIN (arg);
312
313 }
314 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
315 {
316 tree orig_arg = arg;
317 bitmap slots = BITMAP_ALLOC (NULL);
318 bitmap_iterator bi;
319 unsigned bnd_no;
320
321 chkp_find_bound_slots (TREE_TYPE (arg), slots);
322
323 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
324 {
325 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
326 tree new_arg;
327 char offs[25];
328
329 if (DECL_NAME (orig_arg))
330 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
331 else
332 {
333 snprintf (offs, 25, "D.%u", DECL_UID (arg));
334 new_name += offs;
335 }
336 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
337
338 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
339 PARM_DECL,
340 get_identifier (new_name.c_str ()),
341 pointer_bounds_type_node);
342 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
343 DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
344 DECL_ARTIFICIAL (new_arg) = 1;
345 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
346 DECL_CHAIN (arg) = new_arg;
347
348 arg = DECL_CHAIN (arg);
349 }
350 BITMAP_FREE (slots);
351 }
352
353 TREE_TYPE (fndecl) =
354 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
355 }
356
357 /* Return clone created for instrumentation of NODE or NULL. */
358
359 cgraph_node *
360 chkp_maybe_create_clone (tree fndecl)
361 {
362 cgraph_node *node = cgraph_node::get_create (fndecl);
363 cgraph_node *clone = node->instrumented_version;
364
365 gcc_assert (!node->instrumentation_clone);
366
367 if (!clone)
368 {
369 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
370 struct cgraph_edge *e;
371 struct ipa_ref *ref;
372 int i;
373
374 clone = node->create_version_clone (new_decl, vNULL, NULL);
375 clone->externally_visible = node->externally_visible;
376 clone->local = node->local;
377 clone->address_taken = node->address_taken;
378 clone->thunk = node->thunk;
379 clone->alias = node->alias;
380 clone->weakref = node->weakref;
381 clone->cpp_implicit_alias = node->cpp_implicit_alias;
382 clone->instrumented_version = node;
383 clone->orig_decl = fndecl;
384 clone->instrumentation_clone = true;
385 node->instrumented_version = clone;
386
387 if (gimple_has_body_p (fndecl))
388 {
389 /* If function will not be instrumented, then it's instrumented
390 version is a thunk for the original. */
391 if (lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
392 || (flag_chkp_instrument_marked_only
393 && !lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl))))
394 {
395 clone->thunk.thunk_p = true;
396 clone->thunk.add_pointer_bounds_args = true;
397 clone->create_edge (node, NULL, 0, CGRAPH_FREQ_BASE);
398 }
399 else
400 {
401 tree_function_versioning (fndecl, new_decl, NULL, false,
402 NULL, false, NULL, NULL);
403 clone->lowered = true;
404 }
405 }
406
407 /* New params are inserted after versioning because it
408 actually copies args list from the original decl. */
409 chkp_add_bounds_params_to_function (new_decl);
410
411 /* Clones have the same comdat group as originals. */
412 if (node->same_comdat_group
413 || DECL_ONE_ONLY (node->decl))
414 clone->add_to_same_comdat_group (node);
415
416 if (gimple_has_body_p (fndecl))
417 symtab->call_cgraph_insertion_hooks (clone);
418
419 /* Clone all aliases. */
420 for (i = 0; node->iterate_referring (i, ref); i++)
421 if (ref->use == IPA_REF_ALIAS)
422 {
423 struct cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
424 struct cgraph_node *chkp_alias
425 = chkp_maybe_create_clone (alias->decl);
426 chkp_alias->create_reference (clone, IPA_REF_ALIAS, NULL);
427 }
428
429 /* Clone all thunks. */
430 for (e = node->callers; e; e = e->next_caller)
431 if (e->caller->thunk.thunk_p)
432 {
433 struct cgraph_node *thunk
434 = chkp_maybe_create_clone (e->caller->decl);
435 /* Redirect thunk clone edge to the node clone. */
436 thunk->callees->redirect_callee (clone);
437 }
438
439 /* For aliases and thunks we should make sure target is cloned
440 to have proper references and edges. */
441 if (node->thunk.thunk_p)
442 chkp_maybe_create_clone (node->callees->callee->decl);
443 else if (node->alias)
444 {
445 struct cgraph_node *target;
446
447 ref = node->ref_list.first_reference ();
448 if (ref)
449 chkp_maybe_create_clone (ref->referred->decl);
450
451 if (node->alias_target)
452 {
453 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
454 {
455 target = chkp_maybe_create_clone (node->alias_target);
456 clone->alias_target = target->decl;
457 }
458 else
459 clone->alias_target = node->alias_target;
460 }
461 }
462
463 /* Add IPA reference. It's main role is to keep instrumented
464 version reachable while original node is reachable. */
465 ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
466 }
467
468 return clone;
469 }
470
471 /* Create clone for all functions to be instrumented. */
472
473 static unsigned int
474 chkp_versioning (void)
475 {
476 struct cgraph_node *node;
477
478 bitmap_obstack_initialize (NULL);
479
480 FOR_EACH_DEFINED_FUNCTION (node)
481 {
482 if (!node->instrumentation_clone
483 && !node->instrumented_version
484 && !node->alias
485 && !node->thunk.thunk_p
486 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl))
487 && (!flag_chkp_instrument_marked_only
488 || lookup_attribute ("bnd_instrument",
489 DECL_ATTRIBUTES (node->decl)))
490 /* No builtins instrumentation for now. */
491 && DECL_BUILT_IN_CLASS (node->decl) == NOT_BUILT_IN)
492 chkp_maybe_create_clone (node->decl);
493 }
494
495 /* Mark all aliases and thunks of functions with no instrumented
496 version as legacy function. */
497 FOR_EACH_DEFINED_FUNCTION (node)
498 {
499 if (!node->instrumentation_clone
500 && !node->instrumented_version
501 && (node->alias || node->thunk.thunk_p)
502 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
503 DECL_ATTRIBUTES (node->decl)
504 = tree_cons (get_identifier ("bnd_legacy"), NULL,
505 DECL_ATTRIBUTES (node->decl));
506 }
507
508 bitmap_obstack_release (NULL);
509
510 return 0;
511 }
512
513 /* In this pass we remove bodies of functions having
514 instrumented version. Functions with removed bodies
515 become a special kind of thunks to provide a connection
516 between calls to the original version and instrumented
517 function. */
518
519 static unsigned int
520 chkp_produce_thunks (void)
521 {
522 struct cgraph_node *node;
523
524 FOR_EACH_DEFINED_FUNCTION (node)
525 {
526 if (!node->instrumentation_clone
527 && node->instrumented_version
528 && gimple_has_body_p (node->decl)
529 && gimple_has_body_p (node->instrumented_version->decl))
530 {
531 node->release_body ();
532 node->remove_callees ();
533 node->remove_all_references ();
534
535 node->thunk.thunk_p = true;
536 node->thunk.add_pointer_bounds_args = true;
537 node->create_edge (node->instrumented_version, NULL,
538 0, CGRAPH_FREQ_BASE);
539 node->create_reference (node->instrumented_version,
540 IPA_REF_CHKP, NULL);
541 }
542 }
543
544 /* Mark instrumentation clones created for aliases and thunks
545 as insttrumented so they could be removed as unreachable
546 now. */
547 FOR_EACH_DEFINED_FUNCTION (node)
548 {
549 if (node->instrumentation_clone
550 && (node->alias || node->thunk.thunk_p)
551 && !chkp_function_instrumented_p (node->decl))
552 chkp_function_mark_instrumented (node->decl);
553 }
554
555 symtab->remove_unreachable_nodes (true, dump_file);
556
557 return 0;
558 }
559
560 const pass_data pass_data_ipa_chkp_versioning =
561 {
562 SIMPLE_IPA_PASS, /* type */
563 "chkp_versioning", /* name */
564 OPTGROUP_NONE, /* optinfo_flags */
565 TV_NONE, /* tv_id */
566 0, /* properties_required */
567 0, /* properties_provided */
568 0, /* properties_destroyed */
569 0, /* todo_flags_start */
570 0 /* todo_flags_finish */
571 };
572
573 const pass_data pass_data_ipa_chkp_produce_thunks =
574 {
575 SIMPLE_IPA_PASS, /* type */
576 "chkp_cleanup", /* name */
577 OPTGROUP_NONE, /* optinfo_flags */
578 TV_NONE, /* tv_id */
579 0, /* properties_required */
580 0, /* properties_provided */
581 0, /* properties_destroyed */
582 0, /* todo_flags_start */
583 0 /* todo_flags_finish */
584 };
585
586 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
587 {
588 public:
589 pass_ipa_chkp_versioning (gcc::context *ctxt)
590 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
591 {}
592
593 /* opt_pass methods: */
594 virtual opt_pass * clone ()
595 {
596 return new pass_ipa_chkp_versioning (m_ctxt);
597 }
598
599 virtual bool gate (function *)
600 {
601 return flag_check_pointer_bounds;
602 }
603
604 virtual unsigned int execute (function *)
605 {
606 return chkp_versioning ();
607 }
608
609 }; // class pass_ipa_chkp_versioning
610
611 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
612 {
613 public:
614 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
615 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
616 {}
617
618 /* opt_pass methods: */
619 virtual opt_pass * clone ()
620 {
621 return new pass_ipa_chkp_produce_thunks (m_ctxt);
622 }
623
624 virtual bool gate (function *)
625 {
626 return flag_check_pointer_bounds;
627 }
628
629 virtual unsigned int execute (function *)
630 {
631 return chkp_produce_thunks ();
632 }
633
634 }; // class pass_chkp_produce_thunks
635
636 simple_ipa_opt_pass *
637 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
638 {
639 return new pass_ipa_chkp_versioning (ctxt);
640 }
641
642 simple_ipa_opt_pass *
643 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
644 {
645 return new pass_ipa_chkp_produce_thunks (ctxt);
646 }