1 /* Mudflap: narrow-pointer bounds-checking by tree rewriting.
2 Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
3 Contributed by Frank Ch. Eigler <fche@redhat.com>
4 and Graydon Hoare <graydon@redhat.com>
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING. If not, write to the Free
20 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
27 #include "coretypes.h"
29 #include "hard-reg-set.h"
33 #include "basic-block.h"
36 #include "tree-inline.h"
37 #include "tree-gimple.h"
38 #include "tree-flow.h"
39 #include "tree-mudflap.h"
40 #include "tree-dump.h"
41 #include "tree-pass.h"
43 #include "diagnostic.h"
45 #include "langhooks.h"
49 /* Internal function decls */
52 static tree mf_build_string (const char *string);
53 static tree mf_varname_tree (tree);
54 static tree mf_file_function_line_tree (location_t);
56 /* Indirection-related instrumentation. */
57 static void mf_decl_cache_locals (void);
58 static void mf_decl_clear_locals (void);
59 static void mf_xform_derefs (void);
60 static void execute_mudflap_function_ops (void);
62 /* Addressable variables instrumentation. */
63 static void mf_xform_decls (tree, tree);
64 static tree mx_xfn_xform_decls (tree *, int *, void *);
65 static void mx_register_decls (tree, tree *);
66 static void execute_mudflap_function_decls (void);
69 /* ------------------------------------------------------------------------ */
70 /* Some generally helpful functions for mudflap instrumentation. */
72 /* Build a reference to a literal string. */
74 mf_build_string (const char *string)
76 size_t len = strlen (string);
77 tree result = mf_mark (build_string (len + 1, string));
79 TREE_TYPE (result) = build_array_type
80 (char_type_node, build_index_type (build_int_cst (NULL_TREE, len)));
81 TREE_CONSTANT (result) = 1;
82 TREE_INVARIANT (result) = 1;
83 TREE_READONLY (result) = 1;
84 TREE_STATIC (result) = 1;
86 result = build1 (ADDR_EXPR, build_pointer_type (char_type_node), result);
88 return mf_mark (result);
91 /* Create a properly typed STRING_CST node that describes the given
92 declaration. It will be used as an argument for __mf_register().
93 Try to construct a helpful string, including file/function/variable
97 mf_varname_tree (tree decl)
99 static pretty_printer buf_rec;
100 static int initialized = 0;
101 pretty_printer *buf = & buf_rec;
102 const char *buf_contents;
109 pp_construct (buf, /* prefix */ NULL, /* line-width */ 0);
112 pp_clear_output_area (buf);
114 /* Add FILENAME[:LINENUMBER[:COLUMNNUMBER]]. */
116 expanded_location xloc = expand_location (DECL_SOURCE_LOCATION (decl));
117 const char *sourcefile;
118 unsigned sourceline = xloc.line;
119 unsigned sourcecolumn = 0;
120 #ifdef USE_MAPPED_LOCATION
121 sourcecolumn = xloc.column;
123 sourcefile = xloc.file;
124 if (sourcefile == NULL && current_function_decl != NULL_TREE)
125 sourcefile = DECL_SOURCE_FILE (current_function_decl);
126 if (sourcefile == NULL)
127 sourcefile = "<unknown file>";
129 pp_string (buf, sourcefile);
133 pp_string (buf, ":");
134 pp_decimal_int (buf, sourceline);
136 if (sourcecolumn != 0)
138 pp_string (buf, ":");
139 pp_decimal_int (buf, sourcecolumn);
144 if (current_function_decl != NULL_TREE)
147 pp_string (buf, " (");
149 const char *funcname = NULL;
150 if (DECL_NAME (current_function_decl))
151 funcname = lang_hooks.decl_printable_name (current_function_decl, 1);
152 if (funcname == NULL)
153 funcname = "anonymous fn";
155 pp_string (buf, funcname);
157 pp_string (buf, ") ");
160 pp_string (buf, " ");
162 /* Add <variable-declaration>, possibly demangled. */
164 const char *declname = NULL;
166 if (strcmp ("GNU C++", lang_hooks.name) == 0 &&
167 DECL_NAME (decl) != NULL)
169 /* The gcc/cp decl_printable_name hook doesn't do as good a job as
170 the libiberty demangler. */
171 declname = cplus_demangle (IDENTIFIER_POINTER (DECL_NAME (decl)),
172 DMGL_AUTO | DMGL_VERBOSE);
175 if (declname == NULL)
176 declname = lang_hooks.decl_printable_name (decl, 3);
178 if (declname == NULL)
179 declname = "<unnamed variable>";
181 pp_string (buf, declname);
184 /* Return the lot as a new STRING_CST. */
185 buf_contents = pp_base_formatted_text (buf);
186 result = mf_build_string (buf_contents);
187 pp_clear_output_area (buf);
193 /* And another friend, for producing a simpler message. */
196 mf_file_function_line_tree (location_t location)
198 expanded_location xloc = expand_location (location);
199 const char *file = NULL, *colon, *line, *op, *name, *cp;
200 char linecolbuf[30]; /* Enough for two decimal numbers plus a colon. */
204 /* Add FILENAME[:LINENUMBER[:COLUMNNUMBER]]. */
206 if (file == NULL && current_function_decl != NULL_TREE)
207 file = DECL_SOURCE_FILE (current_function_decl);
209 file = "<unknown file>";
213 #ifdef USE_MAPPED_LOCATION
215 sprintf (linecolbuf, "%d:%d", xloc.line, xloc.column);
218 sprintf (linecolbuf, "%d", xloc.line);
225 /* Add (FUNCTION). */
226 name = lang_hooks.decl_printable_name (current_function_decl, 1);
235 string = concat (file, colon, line, op, name, cp, NULL);
236 result = mf_build_string (string);
243 /* global tree nodes */
245 /* Global tree objects for global variables and functions exported by
246 mudflap runtime library. mf_init_extern_trees must be called
247 before using these. */
249 /* uintptr_t (usually "unsigned long") */
250 static GTY (()) tree mf_uintptr_type;
252 /* struct __mf_cache { uintptr_t low; uintptr_t high; }; */
253 static GTY (()) tree mf_cache_struct_type;
255 /* struct __mf_cache * const */
256 static GTY (()) tree mf_cache_structptr_type;
258 /* extern struct __mf_cache __mf_lookup_cache []; */
259 static GTY (()) tree mf_cache_array_decl;
261 /* extern unsigned char __mf_lc_shift; */
262 static GTY (()) tree mf_cache_shift_decl;
264 /* extern uintptr_t __mf_lc_mask; */
265 static GTY (()) tree mf_cache_mask_decl;
267 /* Their function-scope local shadows, used in single-threaded mode only. */
269 /* auto const unsigned char __mf_lc_shift_l; */
270 static GTY (()) tree mf_cache_shift_decl_l;
272 /* auto const uintptr_t __mf_lc_mask_l; */
273 static GTY (()) tree mf_cache_mask_decl_l;
275 /* extern void __mf_check (void *ptr, size_t sz, int type, const char *); */
276 static GTY (()) tree mf_check_fndecl;
278 /* extern void __mf_register (void *ptr, size_t sz, int type, const char *); */
279 static GTY (()) tree mf_register_fndecl;
281 /* extern void __mf_unregister (void *ptr, size_t sz, int type); */
282 static GTY (()) tree mf_unregister_fndecl;
284 /* extern void __mf_init (); */
285 static GTY (()) tree mf_init_fndecl;
287 /* extern int __mf_set_options (const char*); */
288 static GTY (()) tree mf_set_options_fndecl;
291 /* Helper for mudflap_init: construct a decl with the given category,
292 name, and type, mark it an external reference, and pushdecl it. */
294 mf_make_builtin (enum tree_code category, const char *name, tree type)
296 tree decl = mf_mark (build_decl (category, get_identifier (name), type));
297 TREE_PUBLIC (decl) = 1;
298 DECL_EXTERNAL (decl) = 1;
299 lang_hooks.decls.pushdecl (decl);
303 /* Helper for mudflap_init: construct a tree corresponding to the type
304 struct __mf_cache { uintptr_t low; uintptr_t high; };
305 where uintptr_t is the FIELD_TYPE argument. */
307 mf_make_mf_cache_struct_type (tree field_type)
309 /* There is, abominably, no language-independent way to construct a
310 RECORD_TYPE. So we have to call the basic type construction
311 primitives by hand. */
312 tree fieldlo = build_decl (FIELD_DECL, get_identifier ("low"), field_type);
313 tree fieldhi = build_decl (FIELD_DECL, get_identifier ("high"), field_type);
315 tree struct_type = make_node (RECORD_TYPE);
316 DECL_CONTEXT (fieldlo) = struct_type;
317 DECL_CONTEXT (fieldhi) = struct_type;
318 TREE_CHAIN (fieldlo) = fieldhi;
319 TYPE_FIELDS (struct_type) = fieldlo;
320 TYPE_NAME (struct_type) = get_identifier ("__mf_cache");
321 layout_type (struct_type);
326 #define build_function_type_0(rtype) \
327 build_function_type (rtype, void_list_node)
328 #define build_function_type_1(rtype, arg1) \
329 build_function_type (rtype, tree_cons (0, arg1, void_list_node))
330 #define build_function_type_3(rtype, arg1, arg2, arg3) \
331 build_function_type (rtype, tree_cons (0, arg1, tree_cons (0, arg2, \
332 tree_cons (0, arg3, void_list_node))))
333 #define build_function_type_4(rtype, arg1, arg2, arg3, arg4) \
334 build_function_type (rtype, tree_cons (0, arg1, tree_cons (0, arg2, \
335 tree_cons (0, arg3, tree_cons (0, arg4, \
338 /* Initialize the global tree nodes that correspond to mf-runtime.h
343 static bool done = false;
344 tree mf_const_string_type;
345 tree mf_cache_array_type;
346 tree mf_check_register_fntype;
347 tree mf_unregister_fntype;
349 tree mf_set_options_fntype;
355 mf_uintptr_type = lang_hooks.types.type_for_mode (ptr_mode,
358 = build_pointer_type (build_qualified_type
359 (char_type_node, TYPE_QUAL_CONST));
361 mf_cache_struct_type = mf_make_mf_cache_struct_type (mf_uintptr_type);
362 mf_cache_structptr_type = build_pointer_type (mf_cache_struct_type);
363 mf_cache_array_type = build_array_type (mf_cache_struct_type, 0);
364 mf_check_register_fntype =
365 build_function_type_4 (void_type_node, ptr_type_node, size_type_node,
366 integer_type_node, mf_const_string_type);
367 mf_unregister_fntype =
368 build_function_type_3 (void_type_node, ptr_type_node, size_type_node,
371 build_function_type_0 (void_type_node);
372 mf_set_options_fntype =
373 build_function_type_1 (integer_type_node, mf_const_string_type);
375 mf_cache_array_decl = mf_make_builtin (VAR_DECL, "__mf_lookup_cache",
376 mf_cache_array_type);
377 mf_cache_shift_decl = mf_make_builtin (VAR_DECL, "__mf_lc_shift",
378 unsigned_char_type_node);
379 mf_cache_mask_decl = mf_make_builtin (VAR_DECL, "__mf_lc_mask",
381 mf_check_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_check",
382 mf_check_register_fntype);
383 mf_register_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_register",
384 mf_check_register_fntype);
385 mf_unregister_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_unregister",
386 mf_unregister_fntype);
387 mf_init_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_init",
389 mf_set_options_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_set_options",
390 mf_set_options_fntype);
392 #undef build_function_type_4
393 #undef build_function_type_3
394 #undef build_function_type_1
395 #undef build_function_type_0
398 /* ------------------------------------------------------------------------ */
399 /* Memory reference transforms. Perform the mudflap indirection-related
400 tree transforms on the current function.
402 This is the second part of the mudflap instrumentation. It works on
403 low-level GIMPLE using the CFG, because we want to run this pass after
404 tree optimizations have been performed, but we have to preserve the CFG
405 for expansion from trees to RTL. */
408 execute_mudflap_function_ops (void)
410 if (mf_marked_p (current_function_decl))
413 push_gimplify_context ();
415 /* In multithreaded mode, don't cache the lookup cache parameters. */
416 if (! flag_mudflap_threads)
417 mf_decl_cache_locals ();
421 if (! flag_mudflap_threads)
422 mf_decl_clear_locals ();
424 pop_gimplify_context (NULL);
427 /* Create and initialize local shadow variables for the lookup cache
428 globals. Put their decls in the *_l globals for use by
429 mf_build_check_statement_for. */
432 mf_decl_cache_locals (void)
434 tree t, shift_init_stmts, mask_init_stmts;
435 tree_stmt_iterator tsi;
437 /* Build the cache vars. */
438 mf_cache_shift_decl_l
439 = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_shift_decl),
440 "__mf_lookup_shift_l"));
443 = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_mask_decl),
444 "__mf_lookup_mask_l"));
446 /* Build initialization nodes for the cache vars. We just load the
447 globals into the cache variables. */
448 t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_shift_decl_l),
449 mf_cache_shift_decl_l, mf_cache_shift_decl);
450 SET_EXPR_LOCATION (t, DECL_SOURCE_LOCATION (current_function_decl));
451 gimplify_to_stmt_list (&t);
452 shift_init_stmts = t;
454 t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_mask_decl_l),
455 mf_cache_mask_decl_l, mf_cache_mask_decl);
456 SET_EXPR_LOCATION (t, DECL_SOURCE_LOCATION (current_function_decl));
457 gimplify_to_stmt_list (&t);
460 /* Anticipating multiple entry points, we insert the cache vars
461 initializers in each successor of the ENTRY_BLOCK_PTR. */
462 for (tsi = tsi_start (shift_init_stmts);
465 insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR);
467 for (tsi = tsi_start (mask_init_stmts);
470 insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR);
471 bsi_commit_edge_inserts (NULL);
476 mf_decl_clear_locals (void)
478 /* Unset local shadows. */
479 mf_cache_shift_decl_l = NULL_TREE;
480 mf_cache_mask_decl_l = NULL_TREE;
484 mf_build_check_statement_for (tree addr, tree size,
485 block_stmt_iterator *instr_bsi,
486 location_t *locus, tree dirflag)
488 tree_stmt_iterator head, tsi;
489 tree ptrtype = TREE_TYPE (addr);
490 block_stmt_iterator bsi;
491 basic_block cond_bb, then_bb, join_bb;
493 tree cond, t, u, v, l1, l2;
498 /* We first need to split the current basic block, and start altering
499 the CFG. This allows us to insert the statements we're about to
500 construct into the right basic blocks. The label l1 is the label
501 of the block for the THEN clause of the conditional jump we're
502 about to construct, and l2 is the ELSE clause, which is just the
503 continuation of the old statement stream. */
504 l1 = create_artificial_label ();
505 l2 = create_artificial_label ();
506 cond_bb = bb_for_stmt (bsi_stmt (*instr_bsi));
509 if (! bsi_end_p (bsi))
511 /* We're processing a statement in the middle of the block, so
512 we need to split the block. This creates a new block and a new
514 e = split_block (cond_bb, bsi_stmt (bsi));
520 /* We're processing the first statement in the block, so we need
521 to split the incoming edge. This also creates a new block
522 and a new fallthrough edge. */
524 cond_bb = split_edge (find_edge (join_bb->prev_bb, join_bb));
527 /* A recap at this point: join_bb is the basic block at whose head
528 is the gimple statement for which this check expression is being
529 built. cond_bb is the new synthetic basic block which will
530 contain the cache-lookup code, and a conditional that jumps to
531 the cache-miss code or, much more likely, over to join_bb. */
533 /* Create the bb that contains the cache-miss fallback block (mf_check). */
534 then_bb = create_empty_bb (cond_bb);
535 make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
536 make_single_succ_edge (then_bb, join_bb, EDGE_FALLTHRU);
538 /* We expect that the conditional jump we will construct will not
539 be taken very often as it basically is an exception condition. */
540 predict_edge_def (then_bb->pred, PRED_MUDFLAP, NOT_TAKEN);
542 /* Mark the pseudo-fallthrough edge from cond_bb to join_bb. */
543 e = find_edge (cond_bb, join_bb);
544 e->flags = EDGE_FALSE_VALUE;
545 predict_edge_def (e, PRED_MUDFLAP, TAKEN);
547 /* Update dominance info. Note that bb_join's data was
548 updated by split_block. */
549 if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
551 set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
552 set_immediate_dominator (CDI_DOMINATORS, join_bb, cond_bb);
555 /* Build our local variables. */
556 mf_value = create_tmp_var (ptrtype, "__mf_value");
557 mf_elem = create_tmp_var (mf_cache_structptr_type, "__mf_elem");
558 mf_base = create_tmp_var (mf_uintptr_type, "__mf_base");
560 /* Build: __mf_value = <address expression>. */
561 t = build (MODIFY_EXPR, void_type_node, mf_value, unshare_expr (addr));
562 SET_EXPR_LOCUS (t, locus);
563 gimplify_to_stmt_list (&t);
564 head = tsi_start (t);
567 /* Build: __mf_base = (uintptr_t)__mf_value. */
568 t = build (MODIFY_EXPR, void_type_node, mf_base,
569 build1 (NOP_EXPR, mf_uintptr_type, mf_value));
570 SET_EXPR_LOCUS (t, locus);
571 gimplify_to_stmt_list (&t);
572 tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
574 /* Build: __mf_elem = &__mf_lookup_cache [(__mf_base >> __mf_shift)
576 t = build (RSHIFT_EXPR, mf_uintptr_type, mf_base,
577 (flag_mudflap_threads ? mf_cache_shift_decl : mf_cache_shift_decl_l));
578 t = build (BIT_AND_EXPR, mf_uintptr_type, t,
579 (flag_mudflap_threads ? mf_cache_mask_decl : mf_cache_mask_decl_l));
580 t = build (ARRAY_REF,
581 TREE_TYPE (TREE_TYPE (mf_cache_array_decl)),
582 mf_cache_array_decl, t, NULL_TREE, NULL_TREE);
583 t = build1 (ADDR_EXPR, mf_cache_structptr_type, t);
584 t = build (MODIFY_EXPR, void_type_node, mf_elem, t);
585 SET_EXPR_LOCUS (t, locus);
586 gimplify_to_stmt_list (&t);
587 tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
589 /* Quick validity check.
591 if (__mf_elem->low > __mf_base
592 || (__mf_elem_high < __mf_base + sizeof(T) - 1))
595 ... and only if single-threaded:
596 __mf_lookup_shift_1 = f...;
597 __mf_lookup_mask_l = ...;
600 It is expected that this body of code is rarely executed so we mark
601 the edge to the THEN clause of the conditional jump as unlikely. */
603 /* Construct t <-- '__mf_elem->low > __mf_base'. */
604 t = build (COMPONENT_REF, mf_uintptr_type,
605 build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
606 TYPE_FIELDS (mf_cache_struct_type), NULL_TREE);
607 t = build (GT_EXPR, boolean_type_node, t, mf_base);
609 /* Construct '__mf_elem->high < __mf_base + sizeof(T) - 1'.
612 1) u <-- '__mf_elem->high'
613 2) v <-- '__mf_base + sizeof (T) - 1'.
615 Then build 'u <-- (u < v). */
618 u = build (COMPONENT_REF, mf_uintptr_type,
619 build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
620 TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type)), NULL_TREE);
622 v = convert (mf_uintptr_type,
623 size_binop (MINUS_EXPR, size, size_one_node));
624 v = fold (build (PLUS_EXPR, mf_uintptr_type, mf_base, v));
626 u = build (LT_EXPR, boolean_type_node, u, v);
628 /* Build the composed conditional: t <-- 't || u'. Then store the
629 result of the evaluation of 't' in a temporary variable which we
630 can use as the condition for the conditional jump. */
631 t = build (TRUTH_OR_EXPR, boolean_type_node, t, u);
632 cond = create_tmp_var (boolean_type_node, "__mf_unlikely_cond");
633 t = build (MODIFY_EXPR, boolean_type_node, cond, t);
634 gimplify_to_stmt_list (&t);
635 tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
637 /* Build the conditional jump. 'cond' is just a temporary so we can
638 simply build a void COND_EXPR. We do need labels in both arms though. */
639 t = build (COND_EXPR, void_type_node, cond,
640 build (GOTO_EXPR, void_type_node, tree_block_label (then_bb)),
641 build (GOTO_EXPR, void_type_node, tree_block_label (join_bb)));
642 SET_EXPR_LOCUS (t, locus);
643 tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
645 /* At this point, after so much hard work, we have only constructed
646 the conditional jump,
648 if (__mf_elem->low > __mf_base
649 || (__mf_elem_high < __mf_base + sizeof(T) - 1))
651 The lowered GIMPLE tree representing this code is in the statement
652 list starting at 'head'.
654 We can insert this now in the current basic block, i.e. the one that
655 the statement we're instrumenting was originally in. */
656 bsi = bsi_last (cond_bb);
657 for (tsi = head; ! tsi_end_p (tsi); tsi_next (&tsi))
658 bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_CONTINUE_LINKING);
660 /* Now build up the body of the cache-miss handling:
665 This is the body of the conditional. */
667 u = tree_cons (NULL_TREE,
668 mf_file_function_line_tree (locus == NULL ? UNKNOWN_LOCATION
671 u = tree_cons (NULL_TREE, dirflag, u);
672 u = tree_cons (NULL_TREE, size, u);
673 u = tree_cons (NULL_TREE, mf_value, u);
674 t = build_function_call_expr (mf_check_fndecl, u);
675 gimplify_to_stmt_list (&t);
676 head = tsi_start (t);
679 if (! flag_mudflap_threads)
681 t = build (MODIFY_EXPR, void_type_node,
682 mf_cache_shift_decl_l, mf_cache_shift_decl);
683 tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
685 t = build (MODIFY_EXPR, void_type_node,
686 mf_cache_mask_decl_l, mf_cache_mask_decl);
687 tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
690 /* Insert the check code in the THEN block. */
691 bsi = bsi_start (then_bb);
692 for (tsi = head; ! tsi_end_p (tsi); tsi_next (&tsi))
693 bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_CONTINUE_LINKING);
695 *instr_bsi = bsi_start (join_bb);
696 bsi_next (instr_bsi);
700 mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp,
701 location_t *locus, tree dirflag)
703 tree type, ptr_type, addr, size, t;
705 /* Don't instrument read operations. */
706 if (dirflag == integer_zero_node && flag_mudflap_ignore_reads)
709 /* Don't instrument marked nodes. */
710 if (mf_marked_p (*tp))
714 type = TREE_TYPE (t);
715 size = TYPE_SIZE_UNIT (type);
717 switch (TREE_CODE (t))
721 /* Omit checking if we can statically determine that the access is
722 valid. For non-addressable local arrays this is not optional,
723 since we won't have called __mf_register for the object. */
726 op0 = TREE_OPERAND (t, 0);
727 op1 = TREE_OPERAND (t, 1);
728 while (TREE_CODE (op1) == INTEGER_CST)
730 tree dom = TYPE_DOMAIN (TREE_TYPE (op0));
732 /* Test for index in range. Break if not. */
734 || (! TYPE_MIN_VALUE (dom)
735 || ! really_constant_p (TYPE_MIN_VALUE (dom)))
736 || (! TYPE_MAX_VALUE (dom)
737 || ! really_constant_p (TYPE_MAX_VALUE (dom)))
738 || (tree_int_cst_lt (op1, TYPE_MIN_VALUE (dom))
739 || tree_int_cst_lt (TYPE_MAX_VALUE (dom), op1)))
742 /* If we're looking at a non-external VAR_DECL, then the
743 access must be ok. */
744 if (TREE_CODE (op0) == VAR_DECL && !DECL_EXTERNAL (op0))
747 /* Only continue if we're still looking at an array. */
748 if (TREE_CODE (op0) != ARRAY_REF)
751 op1 = TREE_OPERAND (op0, 1);
752 op0 = TREE_OPERAND (op0, 0);
755 /* If we got here, we couldn't statically the check. */
756 ptr_type = build_pointer_type (type);
757 addr = build1 (ADDR_EXPR, ptr_type, t);
762 addr = TREE_OPERAND (t, 0);
763 ptr_type = TREE_TYPE (addr);
766 case ARRAY_RANGE_REF:
767 warning ("mudflap checking not yet implemented for ARRAY_RANGE_REF");
774 /* If we're not dereferencing something, then the access
776 if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
779 field = TREE_OPERAND (t, 1);
781 /* If we're looking at a bit field, then we can't take its address
782 with ADDR_EXPR -- lang_hooks.mark_addressable will error. Do
783 things the hard way with PLUS. */
784 if (DECL_BIT_FIELD_TYPE (field))
786 if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST)
787 size = DECL_SIZE_UNIT (field);
789 addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
790 addr = fold_convert (ptr_type_node, addr);
791 addr = fold (build (PLUS_EXPR, ptr_type_node,
792 addr, fold_convert (ptr_type_node,
793 byte_position (field))));
797 ptr_type = build_pointer_type (type);
798 addr = build1 (ADDR_EXPR, ptr_type, t);
807 /* If we're not dereferencing something, then the access
809 if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
812 bpu = bitsize_int (BITS_PER_UNIT);
813 ofs = convert (bitsizetype, TREE_OPERAND (t, 2));
814 rem = size_binop (TRUNC_MOD_EXPR, ofs, bpu);
815 ofs = size_binop (TRUNC_DIV_EXPR, ofs, bpu);
817 size = convert (bitsizetype, TREE_OPERAND (t, 1));
818 size = size_binop (PLUS_EXPR, size, rem);
819 size = size_binop (CEIL_DIV_EXPR, size, bpu);
820 size = convert (sizetype, size);
822 addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
823 addr = convert (ptr_type_node, addr);
824 addr = fold (build (PLUS_EXPR, ptr_type_node, addr, ofs));
832 mf_build_check_statement_for (addr, size, iter, locus, dirflag);
836 mf_xform_derefs (void)
838 basic_block bb, next;
839 block_stmt_iterator i;
840 int saved_last_basic_block = last_basic_block;
842 bb = ENTRY_BLOCK_PTR ->next_bb;
846 for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
848 tree s = bsi_stmt (i);
850 /* Only a few GIMPLE statements can reference memory. */
851 switch (TREE_CODE (s))
854 mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
856 mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 1), EXPR_LOCUS (s),
861 if (TREE_OPERAND (s, 0) != NULL_TREE)
863 if (TREE_CODE (TREE_OPERAND (s, 0)) == MODIFY_EXPR)
864 mf_xform_derefs_1 (&i, &TREE_OPERAND (TREE_OPERAND (s, 0), 1),
865 EXPR_LOCUS (s), integer_zero_node);
867 mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
878 while (bb && bb->index <= saved_last_basic_block);
881 /* ------------------------------------------------------------------------ */
882 /* ADDR_EXPR transforms. Perform the declaration-related mudflap tree
883 transforms on the current function.
885 This is the first part of the mudflap instrumentation. It works on
886 high-level GIMPLE because after lowering, all variables are moved out
887 of their BIND_EXPR binding context, and we lose liveness information
888 for the declarations we wish to instrument. */
891 execute_mudflap_function_decls (void)
893 if (mf_marked_p (current_function_decl))
896 push_gimplify_context ();
898 mf_xform_decls (DECL_SAVED_TREE (current_function_decl),
899 DECL_ARGUMENTS (current_function_decl));
901 pop_gimplify_context (NULL);
904 /* This struct is passed between mf_xform_decls to store state needed
905 during the traversal searching for objects that have their
907 struct mf_xform_decls_data
913 /* Synthesize a CALL_EXPR and a TRY_FINALLY_EXPR, for this chain of
914 _DECLs if appropriate. Arrange to call the __mf_register function
915 now, and the __mf_unregister function later for each. */
917 mx_register_decls (tree decl, tree *stmt_list)
919 tree finally_stmts = NULL_TREE;
920 tree_stmt_iterator initially_stmts = tsi_start (*stmt_list);
922 while (decl != NULL_TREE)
925 if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
926 /* It must be a non-external, automatic variable. */
927 && ! DECL_EXTERNAL (decl)
928 && ! TREE_STATIC (decl)
929 /* The decl must have its address taken. */
930 && TREE_ADDRESSABLE (decl)
931 /* The type of the variable must be complete. */
932 && COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl))
933 /* The decl hasn't been decomposed somehow. */
934 && DECL_VALUE_EXPR (decl) == NULL
935 /* Don't process the same decl twice. */
936 && ! mf_marked_p (decl))
938 tree size = NULL_TREE, variable_name;
939 tree unregister_fncall, unregister_fncall_params;
940 tree register_fncall, register_fncall_params;
942 size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl)));
944 /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */
945 unregister_fncall_params =
946 tree_cons (NULL_TREE,
947 convert (ptr_type_node,
948 mf_mark (build1 (ADDR_EXPR,
949 build_pointer_type (TREE_TYPE (decl)),
951 tree_cons (NULL_TREE,
953 tree_cons (NULL_TREE,
954 /* __MF_TYPE_STACK */
955 build_int_cst (NULL_TREE, 3),
957 /* __mf_unregister (...) */
958 unregister_fncall = build_function_call_expr (mf_unregister_fndecl,
959 unregister_fncall_params);
961 /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK, "name") */
962 variable_name = mf_varname_tree (decl);
963 register_fncall_params =
964 tree_cons (NULL_TREE,
965 convert (ptr_type_node,
966 mf_mark (build1 (ADDR_EXPR,
967 build_pointer_type (TREE_TYPE (decl)),
969 tree_cons (NULL_TREE,
971 tree_cons (NULL_TREE,
972 /* __MF_TYPE_STACK */
973 build_int_cst (NULL_TREE, 3),
974 tree_cons (NULL_TREE,
978 /* __mf_register (...) */
979 register_fncall = build_function_call_expr (mf_register_fndecl,
980 register_fncall_params);
982 /* Accumulate the two calls. */
983 /* ??? Set EXPR_LOCATION. */
984 gimplify_stmt (®ister_fncall);
985 gimplify_stmt (&unregister_fncall);
987 /* Add the __mf_register call at the current appending point. */
988 if (tsi_end_p (initially_stmts))
989 internal_error ("mudflap ran off end of BIND_EXPR body");
990 tsi_link_before (&initially_stmts, register_fncall, TSI_SAME_STMT);
992 /* Accumulate the FINALLY piece. */
993 append_to_statement_list (unregister_fncall, &finally_stmts);
998 decl = TREE_CHAIN (decl);
1001 /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */
1002 if (finally_stmts != NULL_TREE)
1004 tree t = build (TRY_FINALLY_EXPR, void_type_node,
1005 *stmt_list, finally_stmts);
1007 append_to_statement_list (t, stmt_list);
1012 /* Process every variable mentioned in BIND_EXPRs. */
1014 mx_xfn_xform_decls (tree *t, int *continue_p, void *data)
1016 struct mf_xform_decls_data* d = (struct mf_xform_decls_data*) data;
1018 if (*t == NULL_TREE || *t == error_mark_node)
1026 switch (TREE_CODE (*t))
1030 /* Process function parameters now (but only once). */
1031 mx_register_decls (d->param_decls, &BIND_EXPR_BODY (*t));
1032 d->param_decls = NULL_TREE;
1034 mx_register_decls (BIND_EXPR_VARS (*t), &BIND_EXPR_BODY (*t));
1045 /* Perform the object lifetime tracking mudflap transform on the given function
1046 tree. The tree is mutated in place, with possibly copied subtree nodes.
1048 For every auto variable declared, if its address is ever taken
1049 within the function, then supply its lifetime to the mudflap
1050 runtime with the __mf_register and __mf_unregister calls.
1054 mf_xform_decls (tree fnbody, tree fnparams)
1056 struct mf_xform_decls_data d;
1057 d.param_decls = fnparams;
1058 walk_tree_without_duplicates (&fnbody, mx_xfn_xform_decls, &d);
1062 /* ------------------------------------------------------------------------ */
1063 /* Externally visible mudflap functions. */
1066 /* Mark and return the given tree node to prevent further mudflap
1068 static GTY ((param_is (union tree_node))) htab_t marked_trees = NULL;
1075 if (marked_trees == NULL)
1076 marked_trees = htab_create_ggc (31, htab_hash_pointer, htab_eq_pointer, NULL);
1078 slot = htab_find_slot (marked_trees, t, INSERT);
1084 mf_marked_p (tree t)
1088 if (marked_trees == NULL)
1091 entry = htab_find (marked_trees, t);
1092 return (entry != NULL);
1095 /* Remember given node as a static of some kind: global data,
1096 function-scope static, or an anonymous constant. Its assembler
1099 /* A list of globals whose incomplete declarations we encountered.
1100 Instead of emitting the __mf_register call for them here, it's
1101 delayed until program finish time. If they're still incomplete by
1102 then, warnings are emitted. */
1104 static GTY (()) varray_type deferred_static_decls;
1106 /* A list of statements for calling __mf_register() at startup time. */
1107 static GTY (()) tree enqueued_call_stmt_chain;
1110 mudflap_register_call (tree obj, tree object_size, tree varname)
1112 tree arg, args, call_stmt;
1114 args = tree_cons (NULL_TREE, varname, NULL_TREE);
1116 arg = build_int_cst (NULL_TREE, 4); /* __MF_TYPE_STATIC */
1117 args = tree_cons (NULL_TREE, arg, args);
1119 arg = convert (size_type_node, object_size);
1120 args = tree_cons (NULL_TREE, arg, args);
1122 arg = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (obj)), obj);
1123 arg = convert (ptr_type_node, arg);
1124 args = tree_cons (NULL_TREE, arg, args);
1126 call_stmt = build_function_call_expr (mf_register_fndecl, args);
1128 append_to_statement_list (call_stmt, &enqueued_call_stmt_chain);
1132 mudflap_enqueue_decl (tree obj)
1134 if (mf_marked_p (obj))
1137 /* We don't need to process variable decls that are internally
1138 generated extern. If we did, we'd end up with warnings for them
1139 during mudflap_finish_file (). That would confuse the user,
1140 since the text would refer to variables that don't show up in the
1141 user's source code. */
1142 if (DECL_P (obj) && DECL_EXTERNAL (obj) && DECL_ARTIFICIAL (obj))
1145 if (COMPLETE_TYPE_P (TREE_TYPE (obj)))
1151 object_size = size_in_bytes (TREE_TYPE (obj));
1155 fprintf (dump_file, "enqueue_decl obj=`");
1156 print_generic_expr (dump_file, obj, dump_flags);
1157 fprintf (dump_file, "' size=");
1158 print_generic_expr (dump_file, object_size, dump_flags);
1159 fprintf (dump_file, "\n");
1162 /* NB: the above condition doesn't require TREE_USED or
1163 TREE_ADDRESSABLE. That's because this object may be a global
1164 only used from other compilation units. XXX: Maybe static
1165 objects could require those attributes being set. */
1167 mudflap_register_call (obj, object_size, mf_varname_tree (obj));
1173 if (! deferred_static_decls)
1174 VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list");
1176 /* Ugh, linear search... */
1177 for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1178 if (VARRAY_TREE (deferred_static_decls, i) == obj)
1180 warning ("mudflap cannot track lifetime of %qs",
1181 IDENTIFIER_POINTER (DECL_NAME (obj)));
1185 VARRAY_PUSH_TREE (deferred_static_decls, obj);
1190 mudflap_enqueue_constant (tree obj)
1192 tree object_size, varname;
1194 if (mf_marked_p (obj))
1197 if (TREE_CODE (obj) == STRING_CST)
1198 object_size = build_int_cst (NULL_TREE, TREE_STRING_LENGTH (obj));
1200 object_size = size_in_bytes (TREE_TYPE (obj));
1204 fprintf (dump_file, "enqueue_constant obj=`");
1205 print_generic_expr (dump_file, obj, dump_flags);
1206 fprintf (dump_file, "' size=");
1207 print_generic_expr (dump_file, object_size, dump_flags);
1208 fprintf (dump_file, "\n");
1211 if (TREE_CODE (obj) == STRING_CST)
1212 varname = mf_build_string ("string literal");
1214 varname = mf_build_string ("constant");
1216 mudflap_register_call (obj, object_size, varname);
1220 /* Emit any file-wide instrumentation. */
1222 mudflap_finish_file (void)
1224 tree ctor_statements = NULL_TREE;
1226 /* Try to give the deferred objects one final try. */
1227 if (deferred_static_decls)
1231 for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1233 tree obj = VARRAY_TREE (deferred_static_decls, i);
1235 /* Call enqueue_decl again on the same object it has previously
1236 put into the table. (It won't modify the table this time, so
1237 infinite iteration is not a problem.) */
1238 mudflap_enqueue_decl (obj);
1241 VARRAY_CLEAR (deferred_static_decls);
1244 /* Insert a call to __mf_init. */
1246 tree call2_stmt = build_function_call_expr (mf_init_fndecl, NULL_TREE);
1247 append_to_statement_list (call2_stmt, &ctor_statements);
1250 /* If appropriate, call __mf_set_options to pass along read-ignore mode. */
1251 if (flag_mudflap_ignore_reads)
1253 tree arg = tree_cons (NULL_TREE,
1254 mf_build_string ("-ignore-reads"), NULL_TREE);
1255 tree call_stmt = build_function_call_expr (mf_set_options_fndecl, arg);
1256 append_to_statement_list (call_stmt, &ctor_statements);
1259 /* Append all the enqueued registration calls. */
1260 if (enqueued_call_stmt_chain)
1262 append_to_statement_list (enqueued_call_stmt_chain, &ctor_statements);
1263 enqueued_call_stmt_chain = NULL_TREE;
1266 cgraph_build_static_cdtor ('I', ctor_statements,
1267 MAX_RESERVED_INIT_PRIORITY-1);
1274 return flag_mudflap != 0;
1277 struct tree_opt_pass pass_mudflap_1 =
1279 "mudflap1", /* name */
1280 gate_mudflap, /* gate */
1281 execute_mudflap_function_decls, /* execute */
1284 0, /* static_pass_number */
1286 PROP_gimple_any, /* properties_required */
1287 0, /* properties_provided */
1288 0, /* properties_destroyed */
1289 0, /* todo_flags_start */
1290 TODO_dump_func, /* todo_flags_finish */
1294 struct tree_opt_pass pass_mudflap_2 =
1296 "mudflap2", /* name */
1297 gate_mudflap, /* gate */
1298 execute_mudflap_function_ops, /* execute */
1301 0, /* static_pass_number */
1303 PROP_gimple_leh, /* properties_required */
1304 0, /* properties_provided */
1305 0, /* properties_destroyed */
1306 0, /* todo_flags_start */
1307 TODO_verify_flow | TODO_verify_stmts
1308 | TODO_dump_func, /* todo_flags_finish */
1312 #include "gt-tree-mudflap.h"