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;
105 if (decl == NULL_TREE)
110 pp_construct (buf, /* prefix */ NULL, /* line-width */ 0);
113 pp_clear_output_area (buf);
115 /* Add FILENAME[:LINENUMBER[:COLUMNNUMBER]]. */
117 expanded_location xloc = expand_location (DECL_SOURCE_LOCATION (decl));
118 const char *sourcefile;
119 unsigned sourceline = xloc.line;
120 unsigned sourcecolumn = 0;
121 #ifdef USE_MAPPED_LOCATION
122 sourcecolumn = xloc.column;
124 sourcefile = xloc.file;
125 if (sourcefile == NULL && current_function_decl != NULL_TREE)
126 sourcefile = DECL_SOURCE_FILE (current_function_decl);
127 if (sourcefile == NULL)
128 sourcefile = "<unknown file>";
130 pp_string (buf, sourcefile);
134 pp_string (buf, ":");
135 pp_decimal_int (buf, sourceline);
137 if (sourcecolumn != 0)
139 pp_string (buf, ":");
140 pp_decimal_int (buf, sourcecolumn);
145 if (current_function_decl != NULL_TREE)
148 pp_string (buf, " (");
150 const char *funcname = NULL;
151 if (DECL_NAME (current_function_decl))
152 funcname = lang_hooks.decl_printable_name (current_function_decl, 1);
153 if (funcname == NULL)
154 funcname = "anonymous fn";
156 pp_string (buf, funcname);
158 pp_string (buf, ") ");
161 pp_string (buf, " ");
163 /* Add <variable-declaration>, possibly demangled. */
165 const char *declname = NULL;
167 if (strcmp ("GNU C++", lang_hooks.name) == 0 &&
168 DECL_NAME (decl) != NULL)
170 /* The gcc/cp decl_printable_name hook doesn't do as good a job as
171 the libiberty demangler. */
172 declname = cplus_demangle (IDENTIFIER_POINTER (DECL_NAME (decl)),
173 DMGL_AUTO | DMGL_VERBOSE);
176 if (declname == NULL)
177 declname = lang_hooks.decl_printable_name (decl, 3);
179 if (declname == NULL)
180 declname = "<unnamed variable>";
182 pp_string (buf, declname);
185 /* Return the lot as a new STRING_CST. */
186 buf_contents = pp_base_formatted_text (buf);
187 result = mf_build_string (buf_contents);
188 pp_clear_output_area (buf);
194 /* And another friend, for producing a simpler message. */
197 mf_file_function_line_tree (location_t location)
199 expanded_location xloc = expand_location (location);
200 const char *file = NULL, *colon, *line, *op, *name, *cp;
201 char linecolbuf[30]; /* Enough for two decimal numbers plus a colon. */
205 /* Add FILENAME[:LINENUMBER[:COLUMNNUMBER]]. */
207 if (file == NULL && current_function_decl != NULL_TREE)
208 file = DECL_SOURCE_FILE (current_function_decl);
210 file = "<unknown file>";
214 #ifdef USE_MAPPED_LOCATION
216 sprintf (linecolbuf, "%d:%d", xloc.line, xloc.column);
219 sprintf (linecolbuf, "%d", xloc.line);
226 /* Add (FUNCTION). */
227 name = lang_hooks.decl_printable_name (current_function_decl, 1);
236 string = concat (file, colon, line, op, name, cp, NULL);
237 result = mf_build_string (string);
244 /* global tree nodes */
246 /* Global tree objects for global variables and functions exported by
247 mudflap runtime library. mf_init_extern_trees must be called
248 before using these. */
250 /* uintptr_t (usually "unsigned long") */
251 static GTY (()) tree mf_uintptr_type;
253 /* struct __mf_cache { uintptr_t low; uintptr_t high; }; */
254 static GTY (()) tree mf_cache_struct_type;
256 /* struct __mf_cache * const */
257 static GTY (()) tree mf_cache_structptr_type;
259 /* extern struct __mf_cache __mf_lookup_cache []; */
260 static GTY (()) tree mf_cache_array_decl;
262 /* extern unsigned char __mf_lc_shift; */
263 static GTY (()) tree mf_cache_shift_decl;
265 /* extern uintptr_t __mf_lc_mask; */
266 static GTY (()) tree mf_cache_mask_decl;
268 /* Their function-scope local shadows, used in single-threaded mode only. */
270 /* auto const unsigned char __mf_lc_shift_l; */
271 static GTY (()) tree mf_cache_shift_decl_l;
273 /* auto const uintptr_t __mf_lc_mask_l; */
274 static GTY (()) tree mf_cache_mask_decl_l;
276 /* extern void __mf_check (void *ptr, size_t sz, int type, const char *); */
277 static GTY (()) tree mf_check_fndecl;
279 /* extern void __mf_register (void *ptr, size_t sz, int type, const char *); */
280 static GTY (()) tree mf_register_fndecl;
282 /* extern void __mf_unregister (void *ptr, size_t sz, int type); */
283 static GTY (()) tree mf_unregister_fndecl;
285 /* extern void __mf_init (); */
286 static GTY (()) tree mf_init_fndecl;
288 /* extern int __mf_set_options (const char*); */
289 static GTY (()) tree mf_set_options_fndecl;
292 /* Helper for mudflap_init: construct a decl with the given category,
293 name, and type, mark it an external reference, and pushdecl it. */
295 mf_make_builtin (enum tree_code category, const char *name, tree type)
297 tree decl = mf_mark (build_decl (category, get_identifier (name), type));
298 TREE_PUBLIC (decl) = 1;
299 DECL_EXTERNAL (decl) = 1;
300 lang_hooks.decls.pushdecl (decl);
304 /* Helper for mudflap_init: construct a tree corresponding to the type
305 struct __mf_cache { uintptr_t low; uintptr_t high; };
306 where uintptr_t is the FIELD_TYPE argument. */
308 mf_make_mf_cache_struct_type (tree field_type)
310 /* There is, abominably, no language-independent way to construct a
311 RECORD_TYPE. So we have to call the basic type construction
312 primitives by hand. */
313 tree fieldlo = build_decl (FIELD_DECL, get_identifier ("low"), field_type);
314 tree fieldhi = build_decl (FIELD_DECL, get_identifier ("high"), field_type);
316 tree struct_type = make_node (RECORD_TYPE);
317 DECL_CONTEXT (fieldlo) = struct_type;
318 DECL_CONTEXT (fieldhi) = struct_type;
319 TREE_CHAIN (fieldlo) = fieldhi;
320 TYPE_FIELDS (struct_type) = fieldlo;
321 TYPE_NAME (struct_type) = get_identifier ("__mf_cache");
322 layout_type (struct_type);
327 #define build_function_type_0(rtype) \
328 build_function_type (rtype, void_list_node)
329 #define build_function_type_1(rtype, arg1) \
330 build_function_type (rtype, tree_cons (0, arg1, void_list_node))
331 #define build_function_type_3(rtype, arg1, arg2, arg3) \
332 build_function_type (rtype, tree_cons (0, arg1, tree_cons (0, arg2, \
333 tree_cons (0, arg3, void_list_node))))
334 #define build_function_type_4(rtype, arg1, arg2, arg3, arg4) \
335 build_function_type (rtype, tree_cons (0, arg1, tree_cons (0, arg2, \
336 tree_cons (0, arg3, tree_cons (0, arg4, \
339 /* Initialize the global tree nodes that correspond to mf-runtime.h
344 static bool done = false;
345 tree mf_const_string_type;
346 tree mf_cache_array_type;
347 tree mf_check_register_fntype;
348 tree mf_unregister_fntype;
350 tree mf_set_options_fntype;
356 mf_uintptr_type = lang_hooks.types.type_for_mode (ptr_mode,
359 = build_pointer_type (build_qualified_type
360 (char_type_node, TYPE_QUAL_CONST));
362 mf_cache_struct_type = mf_make_mf_cache_struct_type (mf_uintptr_type);
363 mf_cache_structptr_type = build_pointer_type (mf_cache_struct_type);
364 mf_cache_array_type = build_array_type (mf_cache_struct_type, 0);
365 mf_check_register_fntype =
366 build_function_type_4 (void_type_node, ptr_type_node, size_type_node,
367 integer_type_node, mf_const_string_type);
368 mf_unregister_fntype =
369 build_function_type_3 (void_type_node, ptr_type_node, size_type_node,
372 build_function_type_0 (void_type_node);
373 mf_set_options_fntype =
374 build_function_type_1 (integer_type_node, mf_const_string_type);
376 mf_cache_array_decl = mf_make_builtin (VAR_DECL, "__mf_lookup_cache",
377 mf_cache_array_type);
378 mf_cache_shift_decl = mf_make_builtin (VAR_DECL, "__mf_lc_shift",
379 unsigned_char_type_node);
380 mf_cache_mask_decl = mf_make_builtin (VAR_DECL, "__mf_lc_mask",
382 mf_check_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_check",
383 mf_check_register_fntype);
384 mf_register_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_register",
385 mf_check_register_fntype);
386 mf_unregister_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_unregister",
387 mf_unregister_fntype);
388 mf_init_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_init",
390 mf_set_options_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_set_options",
391 mf_set_options_fntype);
393 #undef build_function_type_4
394 #undef build_function_type_3
395 #undef build_function_type_1
396 #undef build_function_type_0
399 /* ------------------------------------------------------------------------ */
400 /* Memory reference transforms. Perform the mudflap indirection-related
401 tree transforms on the current function.
403 This is the second part of the mudflap instrumentation. It works on
404 low-level GIMPLE using the CFG, because we want to run this pass after
405 tree optimizations have been performed, but we have to preserve the CFG
406 for expansion from trees to RTL. */
409 execute_mudflap_function_ops (void)
411 if (mf_marked_p (current_function_decl))
414 push_gimplify_context ();
416 /* In multithreaded mode, don't cache the lookup cache parameters. */
417 if (! flag_mudflap_threads)
418 mf_decl_cache_locals ();
422 if (! flag_mudflap_threads)
423 mf_decl_clear_locals ();
425 pop_gimplify_context (NULL);
428 /* Create and initialize local shadow variables for the lookup cache
429 globals. Put their decls in the *_l globals for use by
430 mf_build_check_statement_for. */
433 mf_decl_cache_locals (void)
435 tree t, shift_init_stmts, mask_init_stmts;
436 tree_stmt_iterator tsi;
438 /* Build the cache vars. */
439 mf_cache_shift_decl_l
440 = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_shift_decl),
441 "__mf_lookup_shift_l"));
444 = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_mask_decl),
445 "__mf_lookup_mask_l"));
447 /* Build initialization nodes for the cache vars. We just load the
448 globals into the cache variables. */
449 t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_shift_decl_l),
450 mf_cache_shift_decl_l, mf_cache_shift_decl);
451 SET_EXPR_LOCATION (t, DECL_SOURCE_LOCATION (current_function_decl));
452 gimplify_to_stmt_list (&t);
453 shift_init_stmts = t;
455 t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_mask_decl_l),
456 mf_cache_mask_decl_l, mf_cache_mask_decl);
457 SET_EXPR_LOCATION (t, DECL_SOURCE_LOCATION (current_function_decl));
458 gimplify_to_stmt_list (&t);
461 /* Anticipating multiple entry points, we insert the cache vars
462 initializers in each successor of the ENTRY_BLOCK_PTR. */
463 for (tsi = tsi_start (shift_init_stmts);
466 insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR);
468 for (tsi = tsi_start (mask_init_stmts);
471 insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR);
472 bsi_commit_edge_inserts (NULL);
477 mf_decl_clear_locals (void)
479 /* Unset local shadows. */
480 mf_cache_shift_decl_l = NULL_TREE;
481 mf_cache_mask_decl_l = NULL_TREE;
485 mf_build_check_statement_for (tree addr, tree size,
486 block_stmt_iterator *instr_bsi,
487 location_t *locus, tree dirflag)
489 tree_stmt_iterator head, tsi;
490 tree ptrtype = TREE_TYPE (addr);
491 block_stmt_iterator bsi;
492 basic_block cond_bb, then_bb, join_bb;
494 tree cond, t, u, v, l1, l2;
499 /* We first need to split the current basic block, and start altering
500 the CFG. This allows us to insert the statements we're about to
501 construct into the right basic blocks. The label l1 is the label
502 of the block for the THEN clause of the conditional jump we're
503 about to construct, and l2 is the ELSE clause, which is just the
504 continuation of the old statement stream. */
505 l1 = create_artificial_label ();
506 l2 = create_artificial_label ();
507 cond_bb = bb_for_stmt (bsi_stmt (*instr_bsi));
510 if (! bsi_end_p (bsi))
512 e = split_block (cond_bb, bsi_stmt (bsi));
519 cond_bb = create_empty_bb (join_bb->prev_bb);
520 e = make_edge (cond_bb, join_bb, 0);
522 e->flags = EDGE_FALSE_VALUE;
523 then_bb = create_empty_bb (cond_bb);
524 make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
525 make_edge (then_bb, join_bb, EDGE_FALLTHRU);
527 /* We expect that the conditional jump we will construct will not
528 be taken very often as it basically is an exception condition. */
529 predict_edge_def (then_bb->pred, PRED_MUDFLAP, NOT_TAKEN);
531 /* Update dominance info. Note that bb_join's data was
532 updated by split_block. */
533 if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
535 set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
536 set_immediate_dominator (CDI_DOMINATORS, join_bb, cond_bb);
539 /* Build our local variables. */
540 mf_value = create_tmp_var (ptrtype, "__mf_value");
541 mf_elem = create_tmp_var (mf_cache_structptr_type, "__mf_elem");
542 mf_base = create_tmp_var (mf_uintptr_type, "__mf_base");
544 /* Build: __mf_value = <address expression>. */
545 t = build (MODIFY_EXPR, void_type_node, mf_value, unshare_expr (addr));
546 SET_EXPR_LOCUS (t, locus);
547 gimplify_to_stmt_list (&t);
548 head = tsi_start (t);
551 /* Build: __mf_base = (uintptr_t)__mf_value. */
552 t = build (MODIFY_EXPR, void_type_node, mf_base,
553 build1 (NOP_EXPR, mf_uintptr_type, mf_value));
554 SET_EXPR_LOCUS (t, locus);
555 gimplify_to_stmt_list (&t);
556 tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
558 /* Build: __mf_elem = &__mf_lookup_cache [(__mf_base >> __mf_shift)
560 t = build (RSHIFT_EXPR, mf_uintptr_type, mf_base,
561 (flag_mudflap_threads ? mf_cache_shift_decl : mf_cache_shift_decl_l));
562 t = build (BIT_AND_EXPR, mf_uintptr_type, t,
563 (flag_mudflap_threads ? mf_cache_mask_decl : mf_cache_mask_decl_l));
564 t = build (ARRAY_REF,
565 TREE_TYPE (TREE_TYPE (mf_cache_array_decl)),
566 mf_cache_array_decl, t, NULL_TREE, NULL_TREE);
567 t = build1 (ADDR_EXPR, mf_cache_structptr_type, t);
568 t = build (MODIFY_EXPR, void_type_node, mf_elem, t);
569 SET_EXPR_LOCUS (t, locus);
570 gimplify_to_stmt_list (&t);
571 tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
573 /* Quick validity check.
575 if (__mf_elem->low > __mf_base
576 || (__mf_elem_high < __mf_base + sizeof(T) - 1))
579 ... and only if single-threaded:
580 __mf_lookup_shift_1 = f...;
581 __mf_lookup_mask_l = ...;
584 It is expected that this body of code is rarely executed so we mark
585 the edge to the THEN clause of the conditional jump as unlikely. */
587 /* Construct t <-- '__mf_elem->low > __mf_base'. */
588 t = build (COMPONENT_REF, mf_uintptr_type,
589 build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
590 TYPE_FIELDS (mf_cache_struct_type), NULL_TREE);
591 t = build (GT_EXPR, boolean_type_node, t, mf_base);
593 /* Construct '__mf_elem->high < __mf_base + sizeof(T) - 1'.
596 1) u <-- '__mf_elem->high'
597 2) v <-- '__mf_base + sizeof (T) - 1'.
599 Then build 'u <-- (u < v). */
602 u = build (COMPONENT_REF, mf_uintptr_type,
603 build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
604 TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type)), NULL_TREE);
606 v = convert (mf_uintptr_type,
607 size_binop (MINUS_EXPR, size, size_one_node));
608 v = fold (build (PLUS_EXPR, mf_uintptr_type, mf_base, v));
610 u = build (LT_EXPR, boolean_type_node, u, v);
612 /* Build the composed conditional: t <-- 't || u'. Then store the
613 result of the evaluation of 't' in a temporary variable which we
614 can use as the condition for the conditional jump. */
615 t = build (TRUTH_OR_EXPR, boolean_type_node, t, u);
616 cond = create_tmp_var (boolean_type_node, "__mf_unlikely_cond");
617 t = build (MODIFY_EXPR, boolean_type_node, cond, t);
618 gimplify_to_stmt_list (&t);
619 tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
621 /* Build the conditional jump. 'cond' is just a temporary so we can
622 simply build a void COND_EXPR. We do need labels in both arms though. */
623 t = build (COND_EXPR, void_type_node, cond,
624 build (GOTO_EXPR, void_type_node, tree_block_label (then_bb)),
625 build (GOTO_EXPR, void_type_node, tree_block_label (join_bb)));
626 SET_EXPR_LOCUS (t, locus);
627 tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
629 /* At this point, after so much hard work, we have only constructed
630 the conditional jump,
632 if (__mf_elem->low > __mf_base
633 || (__mf_elem_high < __mf_base + sizeof(T) - 1))
635 The lowered GIMPLE tree representing this code is in the statement
636 list starting at 'head'.
638 We can insert this now in the current basic block, ie. the one that
639 the statement we're instrumenting was originally in. */
640 bsi = bsi_last (cond_bb);
641 for (tsi = head; ! tsi_end_p (tsi); tsi_next (&tsi))
642 bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_CONTINUE_LINKING);
644 /* Now build up the body of the cache-miss handling:
649 This is the body of the conditional. */
651 u = tree_cons (NULL_TREE,
652 mf_file_function_line_tree (locus == NULL ? UNKNOWN_LOCATION
655 u = tree_cons (NULL_TREE, dirflag, u);
656 u = tree_cons (NULL_TREE, size, u);
657 u = tree_cons (NULL_TREE, mf_value, u);
658 t = build_function_call_expr (mf_check_fndecl, u);
659 gimplify_to_stmt_list (&t);
660 head = tsi_start (t);
663 if (! flag_mudflap_threads)
665 t = build (MODIFY_EXPR, void_type_node,
666 mf_cache_shift_decl_l, mf_cache_shift_decl);
667 tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
669 t = build (MODIFY_EXPR, void_type_node,
670 mf_cache_mask_decl_l, mf_cache_mask_decl);
671 tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
674 /* Insert the check code in the THEN block. */
675 bsi = bsi_start (then_bb);
676 for (tsi = head; ! tsi_end_p (tsi); tsi_next (&tsi))
677 bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_CONTINUE_LINKING);
679 *instr_bsi = bsi_start (join_bb);
680 bsi_next (instr_bsi);
684 mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp,
685 location_t *locus, tree dirflag)
687 tree type, ptr_type, addr, size, t;
689 /* Don't instrument read operations. */
690 if (dirflag == integer_zero_node && flag_mudflap_ignore_reads)
693 /* Don't instrument marked nodes. */
694 if (mf_marked_p (*tp))
698 type = TREE_TYPE (t);
699 size = TYPE_SIZE_UNIT (type);
701 switch (TREE_CODE (t))
705 /* Omit checking if we can statically determine that the access is
706 valid. For non-addressable local arrays this is not optional,
707 since we won't have called __mf_register for the object. */
710 op0 = TREE_OPERAND (t, 0);
711 op1 = TREE_OPERAND (t, 1);
712 while (TREE_CODE (op1) == INTEGER_CST)
714 tree dom = TYPE_DOMAIN (TREE_TYPE (op0));
716 /* Test for index in range. Break if not. */
718 || (! TYPE_MIN_VALUE (dom)
719 || ! really_constant_p (TYPE_MIN_VALUE (dom)))
720 || (! TYPE_MAX_VALUE (dom)
721 || ! really_constant_p (TYPE_MAX_VALUE (dom)))
722 || (tree_int_cst_lt (op1, TYPE_MIN_VALUE (dom))
723 || tree_int_cst_lt (TYPE_MAX_VALUE (dom), op1)))
726 /* If we're looking at a non-external VAR_DECL, then the
727 access must be ok. */
728 if (TREE_CODE (op0) == VAR_DECL && !DECL_EXTERNAL (op0))
731 /* Only continue if we're still looking at an array. */
732 if (TREE_CODE (op0) != ARRAY_REF)
735 op1 = TREE_OPERAND (op0, 1);
736 op0 = TREE_OPERAND (op0, 0);
739 /* If we got here, we couldn't statically the check. */
740 ptr_type = build_pointer_type (type);
741 addr = build1 (ADDR_EXPR, ptr_type, t);
746 addr = TREE_OPERAND (t, 0);
747 ptr_type = TREE_TYPE (addr);
750 case ARRAY_RANGE_REF:
751 warning ("mudflap checking not yet implemented for ARRAY_RANGE_REF");
758 /* If we're not dereferencing something, then the access
760 if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
763 field = TREE_OPERAND (t, 1);
765 /* If we're looking at a bit field, then we can't take its address
766 with ADDR_EXPR -- lang_hooks.mark_addressable will error. Do
767 things the hard way with PLUS. */
768 if (DECL_BIT_FIELD_TYPE (field))
770 if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST)
771 size = DECL_SIZE_UNIT (field);
773 addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
774 addr = fold_convert (ptr_type_node, addr);
775 addr = fold (build (PLUS_EXPR, ptr_type_node,
776 addr, fold_convert (ptr_type_node,
777 byte_position (field))));
781 ptr_type = build_pointer_type (type);
782 addr = build1 (ADDR_EXPR, ptr_type, t);
791 /* If we're not dereferencing something, then the access
793 if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
796 bpu = bitsize_int (BITS_PER_UNIT);
797 ofs = convert (bitsizetype, TREE_OPERAND (t, 2));
798 rem = size_binop (TRUNC_MOD_EXPR, ofs, bpu);
799 ofs = size_binop (TRUNC_DIV_EXPR, ofs, bpu);
801 size = convert (bitsizetype, TREE_OPERAND (t, 1));
802 size = size_binop (PLUS_EXPR, size, rem);
803 size = size_binop (CEIL_DIV_EXPR, size, bpu);
804 size = convert (sizetype, size);
806 addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
807 addr = convert (ptr_type_node, addr);
808 addr = fold (build (PLUS_EXPR, ptr_type_node, addr, ofs));
816 mf_build_check_statement_for (addr, size, iter, locus, dirflag);
820 mf_xform_derefs (void)
822 basic_block bb, next;
823 block_stmt_iterator i;
824 int saved_last_basic_block = last_basic_block;
826 bb = ENTRY_BLOCK_PTR ->next_bb;
830 for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
832 tree s = bsi_stmt (i);
834 /* Only a few GIMPLE statements can reference memory. */
835 switch (TREE_CODE (s))
838 mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
840 mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 1), EXPR_LOCUS (s),
845 if (TREE_OPERAND (s, 0) != NULL_TREE)
847 if (TREE_CODE (TREE_OPERAND (s, 0)) == MODIFY_EXPR)
848 mf_xform_derefs_1 (&i, &TREE_OPERAND (TREE_OPERAND (s, 0), 1),
849 EXPR_LOCUS (s), integer_zero_node);
851 mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
862 while (bb && bb->index <= saved_last_basic_block);
865 /* ------------------------------------------------------------------------ */
866 /* ADDR_EXPR transforms. Perform the declaration-related mudflap tree
867 transforms on the current function.
869 This is the first part of the mudflap instrumentation. It works on
870 high-level GIMPLE because after lowering, all variables are moved out
871 of their BIND_EXPR binding context, and we lose liveness information
872 for the declarations we wish to instrument. */
875 execute_mudflap_function_decls (void)
877 if (mf_marked_p (current_function_decl))
880 push_gimplify_context ();
882 mf_xform_decls (DECL_SAVED_TREE (current_function_decl),
883 DECL_ARGUMENTS (current_function_decl));
885 pop_gimplify_context (NULL);
888 /* This struct is passed between mf_xform_decls to store state needed
889 during the traversal searching for objects that have their
891 struct mf_xform_decls_data
897 /* Synthesize a CALL_EXPR and a TRY_FINALLY_EXPR, for this chain of
898 _DECLs if appropriate. Arrange to call the __mf_register function
899 now, and the __mf_unregister function later for each. */
901 mx_register_decls (tree decl, tree *stmt_list)
903 tree finally_stmts = NULL_TREE;
904 tree_stmt_iterator initially_stmts = tsi_start (*stmt_list);
906 while (decl != NULL_TREE)
909 if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
910 /* It must be a non-external, automatic variable. */
911 && ! DECL_EXTERNAL (decl)
912 && ! TREE_STATIC (decl)
913 /* The decl must have its address taken. */
914 && TREE_ADDRESSABLE (decl)
915 /* The type of the variable must be complete. */
916 && COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl))
917 /* The decl hasn't been decomposed somehow. */
918 && DECL_VALUE_EXPR (decl) == NULL
919 /* Don't process the same decl twice. */
920 && ! mf_marked_p (decl))
922 tree size = NULL_TREE, variable_name;
923 tree unregister_fncall, unregister_fncall_params;
924 tree register_fncall, register_fncall_params;
926 size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl)));
928 /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */
929 unregister_fncall_params =
930 tree_cons (NULL_TREE,
931 convert (ptr_type_node,
932 mf_mark (build1 (ADDR_EXPR,
933 build_pointer_type (TREE_TYPE (decl)),
935 tree_cons (NULL_TREE,
937 tree_cons (NULL_TREE,
938 /* __MF_TYPE_STACK */
939 build_int_cst (NULL_TREE, 3),
941 /* __mf_unregister (...) */
942 unregister_fncall = build_function_call_expr (mf_unregister_fndecl,
943 unregister_fncall_params);
945 /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK, "name") */
946 variable_name = mf_varname_tree (decl);
947 register_fncall_params =
948 tree_cons (NULL_TREE,
949 convert (ptr_type_node,
950 mf_mark (build1 (ADDR_EXPR,
951 build_pointer_type (TREE_TYPE (decl)),
953 tree_cons (NULL_TREE,
955 tree_cons (NULL_TREE,
956 /* __MF_TYPE_STACK */
957 build_int_cst (NULL_TREE, 3),
958 tree_cons (NULL_TREE,
962 /* __mf_register (...) */
963 register_fncall = build_function_call_expr (mf_register_fndecl,
964 register_fncall_params);
966 /* Accumulate the two calls. */
967 /* ??? Set EXPR_LOCATION. */
968 gimplify_stmt (®ister_fncall);
969 gimplify_stmt (&unregister_fncall);
971 /* Add the __mf_register call at the current appending point. */
972 if (tsi_end_p (initially_stmts))
973 internal_error ("mudflap ran off end of BIND_EXPR body");
974 tsi_link_before (&initially_stmts, register_fncall, TSI_SAME_STMT);
976 /* Accumulate the FINALLY piece. */
977 append_to_statement_list (unregister_fncall, &finally_stmts);
982 decl = TREE_CHAIN (decl);
985 /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */
986 if (finally_stmts != NULL_TREE)
988 tree t = build (TRY_FINALLY_EXPR, void_type_node,
989 *stmt_list, finally_stmts);
991 append_to_statement_list (t, stmt_list);
996 /* Process every variable mentioned in BIND_EXPRs. */
998 mx_xfn_xform_decls (tree *t, int *continue_p, void *data)
1000 struct mf_xform_decls_data* d = (struct mf_xform_decls_data*) data;
1002 if (*t == NULL_TREE || *t == error_mark_node)
1010 switch (TREE_CODE (*t))
1014 /* Process function parameters now (but only once). */
1015 mx_register_decls (d->param_decls, &BIND_EXPR_BODY (*t));
1016 d->param_decls = NULL_TREE;
1018 mx_register_decls (BIND_EXPR_VARS (*t), &BIND_EXPR_BODY (*t));
1029 /* Perform the object lifetime tracking mudflap transform on the given function
1030 tree. The tree is mutated in place, with possibly copied subtree nodes.
1032 For every auto variable declared, if its address is ever taken
1033 within the function, then supply its lifetime to the mudflap
1034 runtime with the __mf_register and __mf_unregister calls.
1038 mf_xform_decls (tree fnbody, tree fnparams)
1040 struct mf_xform_decls_data d;
1041 d.param_decls = fnparams;
1042 walk_tree_without_duplicates (&fnbody, mx_xfn_xform_decls, &d);
1046 /* ------------------------------------------------------------------------ */
1047 /* Externally visible mudflap functions. */
1050 /* Mark and return the given tree node to prevent further mudflap
1052 static GTY ((param_is (union tree_node))) htab_t marked_trees = NULL;
1059 if (marked_trees == NULL)
1060 marked_trees = htab_create_ggc (31, htab_hash_pointer, htab_eq_pointer, NULL);
1062 slot = htab_find_slot (marked_trees, t, INSERT);
1068 mf_marked_p (tree t)
1072 if (marked_trees == NULL)
1075 entry = htab_find (marked_trees, t);
1076 return (entry != NULL);
1079 /* Remember given node as a static of some kind: global data,
1080 function-scope static, or an anonymous constant. Its assembler
1083 /* A list of globals whose incomplete declarations we encountered.
1084 Instead of emitting the __mf_register call for them here, it's
1085 delayed until program finish time. If they're still incomplete by
1086 then, warnings are emitted. */
1088 static GTY (()) varray_type deferred_static_decls;
1090 /* A list of statements for calling __mf_register() at startup time. */
1091 static GTY (()) tree enqueued_call_stmt_chain;
1094 mudflap_register_call (tree obj, tree object_size, tree varname)
1096 tree arg, args, call_stmt;
1098 args = tree_cons (NULL_TREE, varname, NULL_TREE);
1100 arg = build_int_cst (NULL_TREE, 4); /* __MF_TYPE_STATIC */
1101 args = tree_cons (NULL_TREE, arg, args);
1103 arg = convert (size_type_node, object_size);
1104 args = tree_cons (NULL_TREE, arg, args);
1106 arg = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (obj)), obj);
1107 arg = convert (ptr_type_node, arg);
1108 args = tree_cons (NULL_TREE, arg, args);
1110 call_stmt = build_function_call_expr (mf_register_fndecl, args);
1112 append_to_statement_list (call_stmt, &enqueued_call_stmt_chain);
1116 mudflap_enqueue_decl (tree obj)
1118 if (mf_marked_p (obj))
1121 /* We don't need to process variable decls that are internally
1122 generated extern. If we did, we'd end up with warnings for them
1123 during mudflap_finish_file (). That would confuse the user,
1124 since the text would refer to variables that don't show up in the
1125 user's source code. */
1126 if (DECL_P (obj) && DECL_EXTERNAL (obj) && DECL_ARTIFICIAL (obj))
1129 if (COMPLETE_TYPE_P (TREE_TYPE (obj)))
1135 object_size = size_in_bytes (TREE_TYPE (obj));
1139 fprintf (dump_file, "enqueue_decl obj=`");
1140 print_generic_expr (dump_file, obj, dump_flags);
1141 fprintf (dump_file, "' size=");
1142 print_generic_expr (dump_file, object_size, dump_flags);
1143 fprintf (dump_file, "\n");
1146 /* NB: the above condition doesn't require TREE_USED or
1147 TREE_ADDRESSABLE. That's because this object may be a global
1148 only used from other compilation units. XXX: Maybe static
1149 objects could require those attributes being set. */
1151 mudflap_register_call (obj, object_size, mf_varname_tree (obj));
1157 if (! deferred_static_decls)
1158 VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list");
1160 /* Ugh, linear search... */
1161 for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1162 if (VARRAY_TREE (deferred_static_decls, i) == obj)
1164 warning ("mudflap cannot track lifetime of `%s'",
1165 IDENTIFIER_POINTER (DECL_NAME (obj)));
1169 VARRAY_PUSH_TREE (deferred_static_decls, obj);
1174 mudflap_enqueue_constant (tree obj)
1176 tree object_size, varname;
1178 if (mf_marked_p (obj))
1181 if (TREE_CODE (obj) == STRING_CST)
1182 object_size = build_int_cst (NULL_TREE, TREE_STRING_LENGTH (obj));
1184 object_size = size_in_bytes (TREE_TYPE (obj));
1188 fprintf (dump_file, "enqueue_constant obj=`");
1189 print_generic_expr (dump_file, obj, dump_flags);
1190 fprintf (dump_file, "' size=");
1191 print_generic_expr (dump_file, object_size, dump_flags);
1192 fprintf (dump_file, "\n");
1195 if (TREE_CODE (obj) == STRING_CST)
1196 varname = mf_build_string ("string literal");
1198 varname = mf_build_string ("constant");
1200 mudflap_register_call (obj, object_size, varname);
1204 /* Emit any file-wide instrumentation. */
1206 mudflap_finish_file (void)
1208 tree ctor_statements = NULL_TREE;
1210 /* Try to give the deferred objects one final try. */
1211 if (deferred_static_decls)
1215 for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1217 tree obj = VARRAY_TREE (deferred_static_decls, i);
1219 /* Call enqueue_decl again on the same object it has previously
1220 put into the table. (It won't modify the table this time, so
1221 infinite iteration is not a problem.) */
1222 mudflap_enqueue_decl (obj);
1225 VARRAY_CLEAR (deferred_static_decls);
1228 /* Insert a call to __mf_init. */
1230 tree call2_stmt = build_function_call_expr (mf_init_fndecl, NULL_TREE);
1231 append_to_statement_list (call2_stmt, &ctor_statements);
1234 /* If appropriate, call __mf_set_options to pass along read-ignore mode. */
1235 if (flag_mudflap_ignore_reads)
1237 tree arg = tree_cons (NULL_TREE,
1238 mf_build_string ("-ignore-reads"), NULL_TREE);
1239 tree call_stmt = build_function_call_expr (mf_set_options_fndecl, arg);
1240 append_to_statement_list (call_stmt, &ctor_statements);
1243 /* Append all the enqueued registration calls. */
1244 if (enqueued_call_stmt_chain)
1246 append_to_statement_list (enqueued_call_stmt_chain, &ctor_statements);
1247 enqueued_call_stmt_chain = NULL_TREE;
1250 cgraph_build_static_cdtor ('I', ctor_statements,
1251 MAX_RESERVED_INIT_PRIORITY-1);
1258 return flag_mudflap != 0;
1261 struct tree_opt_pass pass_mudflap_1 =
1263 "mudflap1", /* name */
1264 gate_mudflap, /* gate */
1265 execute_mudflap_function_decls, /* execute */
1268 0, /* static_pass_number */
1270 PROP_gimple_any, /* properties_required */
1271 0, /* properties_provided */
1272 0, /* properties_destroyed */
1273 0, /* todo_flags_start */
1274 TODO_dump_func, /* todo_flags_finish */
1278 struct tree_opt_pass pass_mudflap_2 =
1280 "mudflap2", /* name */
1281 gate_mudflap, /* gate */
1282 execute_mudflap_function_ops, /* execute */
1285 0, /* static_pass_number */
1287 PROP_gimple_leh, /* properties_required */
1288 0, /* properties_provided */
1289 0, /* properties_destroyed */
1290 0, /* todo_flags_start */
1291 TODO_verify_flow | TODO_verify_stmts
1292 | TODO_dump_func, /* todo_flags_finish */
1296 #include "gt-tree-mudflap.h"