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"
32 #include "tree-inline.h"
33 #include "tree-gimple.h"
34 #include "tree-flow.h"
35 #include "tree-mudflap.h"
36 #include "tree-dump.h"
37 #include "tree-pass.h"
39 #include "diagnostic.h"
41 #include "langhooks.h"
44 /* Internal function decls */
46 static void mf_xform_derefs (tree);
47 static void mf_xform_decls (tree, tree);
48 static void mf_init_extern_trees (void);
49 static void mf_decl_cache_locals (tree *);
50 static void mf_decl_clear_locals (void);
51 static tree mf_varname_tree (tree);
52 static tree mx_xfn_xform_decls (tree *, int *, void *);
54 static void mx_register_decls (tree, tree *);
57 /* extern mudflap functions */
59 static GTY ((param_is (union tree_node))) htab_t marked_trees = NULL;
62 /* Mark and return the given tree node to prevent further mudflap
69 if (marked_trees == NULL)
70 marked_trees = htab_create_ggc (31, htab_hash_pointer, htab_eq_pointer, NULL);
72 slot = htab_find_slot (marked_trees, t, INSERT);
83 if (marked_trees == NULL)
86 entry = htab_find (marked_trees, t);
87 return (entry != NULL);
91 mf_build_string (const char *string)
93 size_t len = strlen (string);
94 tree result = mf_mark (build_string (len + 1, string));
97 = build_array_type (char_type_node,
98 build_index_type (build_int_2 (len, 0)));
99 TREE_CONSTANT (result) = 1;
100 TREE_INVARIANT (result) = 1;
101 TREE_READONLY (result) = 1;
102 TREE_STATIC (result) = 1;
104 result = build1 (ADDR_EXPR, build_pointer_type (char_type_node), result);
106 return mf_mark (result);
109 /* Perform the declaration-related mudflap tree transforms on the
110 given function. Update its DECL_SAVED_TREE. */
113 mudflap_function_decls (void)
115 if (mf_marked_p (current_function_decl))
118 push_gimplify_context ();
120 mf_init_extern_trees ();
121 mf_xform_decls (DECL_SAVED_TREE (current_function_decl),
122 DECL_ARGUMENTS (current_function_decl));
124 pop_gimplify_context (NULL);
130 return flag_mudflap != 0;
133 struct tree_opt_pass pass_mudflap_1 =
135 "mudflap1", /* name */
136 gate_mudflap, /* gate */
137 mudflap_function_decls, /* execute */
140 0, /* static_pass_number */
142 PROP_gimple_any, /* properties_required */
143 0, /* properties_provided */
144 0, /* properties_destroyed */
145 0, /* todo_flags_start */
146 TODO_dump_func /* todo_flags_finish */
150 /* Same as above, for the indirection-related transforms. */
153 mudflap_function_ops (void)
155 if (mf_marked_p (current_function_decl))
158 push_gimplify_context ();
160 /* In multithreaded mode, don't cache the lookup cache parameters. */
161 if (! flag_mudflap_threads)
162 mf_decl_cache_locals (&DECL_SAVED_TREE (current_function_decl));
164 mf_xform_derefs (DECL_SAVED_TREE (current_function_decl));
166 if (! flag_mudflap_threads)
167 mf_decl_clear_locals ();
169 pop_gimplify_context (NULL);
172 struct tree_opt_pass pass_mudflap_2 =
174 "mudflap2", /* name */
175 gate_mudflap, /* gate */
176 mudflap_function_ops, /* execute */
179 0, /* static_pass_number */
181 PROP_gimple_leh, /* properties_required */
182 0, /* properties_provided */
183 0, /* properties_destroyed */
184 0, /* todo_flags_start */
185 TODO_dump_func /* todo_flags_finish */
188 /* global tree nodes */
190 /* Global tree objects for global variables and functions exported by
191 mudflap runtime library. mf_init_extern_trees must be called
192 before using these. */
194 /* uintptr_t (usually "unsigned long") */
195 static GTY (()) tree mf_uintptr_type;
197 /* struct __mf_cache { uintptr_t low; uintptr_t high; }; */
198 static GTY (()) tree mf_cache_struct_type;
200 /* struct __mf_cache * const */
201 static GTY (()) tree mf_cache_structptr_type;
203 /* extern struct __mf_cache __mf_lookup_cache []; */
204 static GTY (()) tree mf_cache_array_decl;
206 /* extern const unsigned char __mf_lc_shift; */
207 static GTY (()) tree mf_cache_shift_decl;
209 /* extern const uintptr_t __mf_lc_mask; */
210 static GTY (()) tree mf_cache_mask_decl;
212 /* Their function-scope local shadows, used in single-threaded mode only. */
214 /* auto const unsigned char __mf_lc_shift_l; */
215 static GTY (()) tree mf_cache_shift_decl_l;
217 /* auto const uintptr_t __mf_lc_mask_l; */
218 static GTY (()) tree mf_cache_mask_decl_l;
220 /* extern void __mf_check (void *ptr, size_t sz, int type, const char *); */
221 static GTY (()) tree mf_check_fndecl;
223 /* extern void __mf_register (void *ptr, size_t sz, int type, const char *); */
224 static GTY (()) tree mf_register_fndecl;
226 /* extern void __mf_unregister (void *ptr, size_t sz); */
227 static GTY (()) tree mf_unregister_fndecl;
230 /* Initialize the global tree nodes that correspond to mf-runtime.h
233 mf_init_extern_trees (void)
235 static bool done = false;
241 mf_uintptr_type = TREE_TYPE (mflang_lookup_decl ("uintptr_t"));
242 mf_cache_array_decl = mf_mark (mflang_lookup_decl ("__mf_lookup_cache"));
243 mf_cache_struct_type = TREE_TYPE (TREE_TYPE (mf_cache_array_decl));
244 mf_cache_structptr_type = build_pointer_type (mf_cache_struct_type);
245 mf_cache_shift_decl = mf_mark (mflang_lookup_decl ("__mf_lc_shift"));
246 mf_cache_mask_decl = mf_mark (mflang_lookup_decl ("__mf_lc_mask"));
247 mf_check_fndecl = mflang_lookup_decl ("__mf_check");
248 mf_register_fndecl = mflang_lookup_decl ("__mf_register");
249 mf_unregister_fndecl = mflang_lookup_decl ("__mf_unregister");
254 /* Create and initialize local shadow variables for the lookup cache
255 globals. Put their decls in the *_l globals for use by
256 mf_build_check_statement_for. */
259 mf_decl_cache_locals (tree* body)
261 tree_stmt_iterator i = tsi_start (*body);
264 mf_cache_shift_decl_l
265 = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_shift_decl),
266 "__mf_lookup_shift_l"));
269 = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_mask_decl),
270 "__mf_lookup_mask_l"));
272 /* Build initialization nodes for them. */
273 t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_shift_decl_l),
274 mf_cache_shift_decl_l, mf_cache_shift_decl);
275 annotate_with_locus (t, DECL_SOURCE_LOCATION (current_function_decl));
277 tsi_link_before (&i, t, TSI_NEW_STMT);
279 t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_mask_decl_l),
280 mf_cache_mask_decl_l, mf_cache_mask_decl);
281 annotate_with_locus (t, DECL_SOURCE_LOCATION (current_function_decl));
283 tsi_link_before (&i, t, TSI_NEW_STMT);
288 mf_decl_clear_locals (void)
290 /* Unset local shadows. */
291 mf_cache_shift_decl_l = NULL_TREE;
292 mf_cache_mask_decl_l = NULL_TREE;
295 /* Create a properly typed STRING_CST node that describes the given
296 declaration. It will be used as an argument for __mf_register().
297 Try to construct a helpful string, including file/function/variable
301 mf_varname_tree (tree decl)
303 static pretty_printer buf_rec;
304 static int initialized = 0;
305 pretty_printer *buf = & buf_rec;
306 const char *buf_contents;
309 if (decl == NULL_TREE)
314 pp_construct (buf, /* prefix */ NULL, /* line-width */ 0);
317 pp_clear_output_area (buf);
319 /* Add FILENAME[:LINENUMBER]. */
321 const char *sourcefile;
324 sourcefile = DECL_SOURCE_FILE (decl);
325 if (sourcefile == NULL && current_function_decl != NULL_TREE)
326 sourcefile = DECL_SOURCE_FILE (current_function_decl);
327 if (sourcefile == NULL)
328 sourcefile = "<unknown file>";
330 pp_string (buf, sourcefile);
332 sourceline = DECL_SOURCE_LINE (decl);
335 pp_string (buf, ":");
336 pp_decimal_int (buf, sourceline);
340 if (current_function_decl != NULL_TREE)
342 /* Add (FUNCTION): */
343 pp_string (buf, " (");
345 const char *funcname = NULL;
346 if (DECL_NAME (current_function_decl))
347 funcname = lang_hooks.decl_printable_name (current_function_decl, 1);
348 if (funcname == NULL)
349 funcname = "anonymous fn";
351 pp_string (buf, funcname);
353 pp_string (buf, ") ");
356 pp_string (buf, " ");
358 /* Add <variable-declaration>, possibly demangled. */
360 const char *declname = NULL;
362 if (strcmp ("GNU C++", lang_hooks.name) == 0 &&
363 DECL_NAME (decl) != NULL)
365 /* The gcc/cp decl_printable_name hook doesn't do as good a job as
366 the libiberty demangler. */
367 declname = cplus_demangle (IDENTIFIER_POINTER (DECL_NAME (decl)),
368 DMGL_AUTO | DMGL_VERBOSE);
371 if (declname == NULL)
372 declname = lang_hooks.decl_printable_name (decl, 3);
374 if (declname == NULL)
375 declname = "<unnamed variable>";
377 pp_string (buf, declname);
380 /* Return the lot as a new STRING_CST. */
381 buf_contents = pp_base_formatted_text (buf);
382 result = mf_build_string (buf_contents);
383 pp_clear_output_area (buf);
389 /* And another friend, for producing a simpler message. */
392 mf_file_function_line_tree (location_t *locus)
394 const char *file = NULL, *colon, *line, *op, *name, *cp;
402 if (file == NULL && current_function_decl != NULL_TREE)
403 file = DECL_SOURCE_FILE (current_function_decl);
405 file = "<unknown file>";
407 /* Add :LINENUMBER. */
408 if (locus != NULL && locus->line > 0)
410 sprintf (linebuf, "%d", locus->line);
417 /* Add (FUNCTION). */
418 name = lang_hooks.decl_printable_name (current_function_decl, 1);
427 string = concat (file, colon, line, op, name, cp, NULL);
428 result = mf_build_string (string);
436 mf_build_check_statement_for (tree addr, tree size, tree_stmt_iterator *iter,
437 location_t *locus, tree dirflag)
439 tree ptrtype = TREE_TYPE (addr);
440 tree stmt, cond, t, u, v;
445 /* Build our local variables. */
446 mf_value = create_tmp_var (ptrtype, "__mf_value");
447 mf_elem = create_tmp_var (mf_cache_structptr_type, "__mf_elem");
448 mf_base = create_tmp_var (mf_uintptr_type, "__mf_base");
450 /* Build: __mf_value = <address expression>. */
451 stmt = build (MODIFY_EXPR, void_type_node, mf_value, addr);
453 annotate_with_locus (stmt, *locus);
454 gimplify_stmt (&stmt);
455 tsi_link_before (iter, stmt, TSI_SAME_STMT);
457 /* Build: __mf_base = (uintptr_t)__mf_value. */
458 stmt = build (MODIFY_EXPR, void_type_node, mf_base,
459 build1 (NOP_EXPR, mf_uintptr_type, mf_value));
461 annotate_with_locus (stmt, *locus);
462 gimplify_stmt (&stmt);
463 tsi_link_before (iter, stmt, TSI_SAME_STMT);
465 /* Build: __mf_elem = &__mf_lookup_cache [(__mf_base >> __mf_shift)
467 t = build (RSHIFT_EXPR, mf_uintptr_type, mf_base,
468 (flag_mudflap_threads ? mf_cache_shift_decl : mf_cache_shift_decl_l));
469 t = build (BIT_AND_EXPR, mf_uintptr_type, t,
470 (flag_mudflap_threads ? mf_cache_mask_decl : mf_cache_mask_decl_l));
471 t = build (ARRAY_REF,
472 TREE_TYPE (TREE_TYPE (mf_cache_array_decl)),
473 mf_cache_array_decl, t);
474 t = build1 (ADDR_EXPR, mf_cache_structptr_type, t);
475 stmt = build (MODIFY_EXPR, void_type_node, mf_elem, t);
477 annotate_with_locus (stmt, *locus);
478 gimplify_stmt (&stmt);
479 tsi_link_before (iter, stmt, TSI_SAME_STMT);
481 /* Quick validity check.
482 if (__builtin_expect ((__mf_elem->low > __mf_base)
483 | (__mf_elem_high < __mf_base + sizeof(T) - 1),
487 ... and only if single-threaded:
488 __mf_lookup_shift_1 = f...;
489 __mf_lookup_mask_l = ...;
494 t = build (COMPONENT_REF, mf_uintptr_type,
495 build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
496 TYPE_FIELDS (mf_cache_struct_type));
498 /* __mf_elem->high */
499 u = build (COMPONENT_REF, mf_uintptr_type,
500 build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
501 TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type)));
503 /* __mf_base + sizeof (T) - 1 */
504 v = size_binop (MINUS_EXPR, size, size_one_node);
505 v = convert (mf_uintptr_type, v);
506 v = fold (build (PLUS_EXPR, mf_uintptr_type, mf_base, v));
508 t = build (TRUTH_OR_EXPR, boolean_type_node,
509 build (GT_EXPR, boolean_type_node, t, mf_base),
510 build (LT_EXPR, boolean_type_node, u, v));
512 /* Mark condition as UNLIKELY using __builtin_expect. */
513 u = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
514 u = tree_cons (NULL_TREE, convert (long_integer_type_node, t), u);
515 cond = build_function_call_expr (built_in_decls[BUILT_IN_EXPECT], u);
517 /* Build up the body of the cache-miss handling:
518 __mf_check(); refresh *_l vars. */
522 u = tree_cons (NULL_TREE, mf_file_function_line_tree (locus), NULL_TREE);
523 u = tree_cons (NULL_TREE, dirflag, u);
524 u = tree_cons (NULL_TREE, size, u);
525 u = tree_cons (NULL_TREE, mf_value, u);
526 t = build_function_call_expr (mf_check_fndecl, u);
527 append_to_statement_list (t, &stmt);
529 if (! flag_mudflap_threads)
531 t = build (MODIFY_EXPR, void_type_node,
532 mf_cache_shift_decl_l, mf_cache_shift_decl);
533 append_to_statement_list (t, &stmt);
535 t = build (MODIFY_EXPR, void_type_node,
536 mf_cache_mask_decl_l, mf_cache_mask_decl);
537 append_to_statement_list (t, &stmt);
540 stmt = build (COND_EXPR, void_type_node, cond, stmt, build_empty_stmt ());
542 annotate_with_locus (stmt, *locus);
543 gimplify_to_stmt_list (&stmt);
544 lower_stmt_body (stmt, NULL);
545 tsi_link_before (iter, stmt, TSI_SAME_STMT);
549 mf_xform_derefs_1 (tree_stmt_iterator *iter, tree *tp,
550 location_t *locus, tree dirflag)
552 tree type, ptr_type, addr, size, t;
554 /* Don't instrument read operations. */
555 if (dirflag == integer_zero_node && flag_mudflap_ignore_reads)
559 type = TREE_TYPE (t);
560 size = TYPE_SIZE_UNIT (type);
562 switch (TREE_CODE (t))
566 /* Omit checking if we can statically determine that the access is
567 valid. For non-addressable local arrays this is not optional,
568 since we won't have called __mf_register for the object. */
571 op0 = TREE_OPERAND (t, 0);
572 op1 = TREE_OPERAND (t, 1);
573 while (TREE_CODE (op1) == INTEGER_CST)
575 tree dom = TYPE_DOMAIN (TREE_TYPE (op0));
577 /* Test for index in range. Break if not. */
580 if (!TYPE_MIN_VALUE (dom) || !really_constant_p (TYPE_MIN_VALUE (dom)))
582 if (!TYPE_MAX_VALUE (dom) || !really_constant_p (TYPE_MAX_VALUE (dom)))
584 if (tree_int_cst_lt (op1, TYPE_MIN_VALUE (dom))
585 || tree_int_cst_lt (TYPE_MAX_VALUE (dom), op1))
588 /* If we're looking at a non-external VAR_DECL, then the
589 access must be ok. */
590 if (TREE_CODE (op0) == VAR_DECL && !DECL_EXTERNAL (op0))
593 /* Only continue if we're still looking at an array. */
594 if (TREE_CODE (op0) != ARRAY_REF)
597 op1 = TREE_OPERAND (op0, 1);
598 op0 = TREE_OPERAND (op0, 0);
601 /* If we got here, we couldn't statically the check. */
602 ptr_type = build_pointer_type (type);
603 addr = build1 (ADDR_EXPR, ptr_type, t);
608 addr = TREE_OPERAND (t, 0);
609 ptr_type = TREE_TYPE (addr);
612 case ARRAY_RANGE_REF:
613 warning ("mudflap checking not yet implemented for ARRAY_RANGE_REF");
620 /* If we're not dereferencing something, then the access
622 if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
625 field = TREE_OPERAND (t, 1);
627 /* If we're looking at a bit field, then we can't take its address
628 with ADDR_EXPR -- lang_hooks.mark_addressable will error. Do
629 things the hard way with PLUS. */
630 if (DECL_BIT_FIELD_TYPE (field))
632 size = bitsize_int (BITS_PER_UNIT);
633 size = size_binop (CEIL_DIV_EXPR, DECL_SIZE (field), size);
634 size = convert (sizetype, size);
636 addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
637 addr = convert (ptr_type_node, addr);
638 addr = fold (build (PLUS_EXPR, ptr_type_node,
639 addr, byte_position (field)));
643 ptr_type = build_pointer_type (type);
644 addr = build1 (ADDR_EXPR, ptr_type, t);
653 /* If we're not dereferencing something, then the access
655 if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
658 bpu = bitsize_int (BITS_PER_UNIT);
659 ofs = convert (bitsizetype, TREE_OPERAND (t, 2));
660 rem = size_binop (TRUNC_MOD_EXPR, ofs, bpu);
661 ofs = size_binop (TRUNC_DIV_EXPR, ofs, bpu);
663 size = convert (bitsizetype, TREE_OPERAND (t, 1));
664 size = size_binop (PLUS_EXPR, size, rem);
665 size = size_binop (CEIL_DIV_EXPR, size, bpu);
666 size = convert (sizetype, size);
668 addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
669 addr = convert (ptr_type_node, addr);
670 addr = fold (build (PLUS_EXPR, ptr_type_node, addr, ofs));
678 mf_build_check_statement_for (addr, size, iter, locus, dirflag);
682 mf_xform_derefs (tree fnbody)
684 tree_stmt_iterator i = tsi_start (fnbody);
686 for (i = tsi_start (fnbody); !tsi_end_p (i); tsi_next (&i))
688 tree s = tsi_stmt (i);
690 /* Only a few GIMPLE statements can reference memory. */
691 switch (TREE_CODE (s))
693 case MODIFY_EXPR: /* This includes INIT_EXPR after gimplification. */
694 mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
696 mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 1), EXPR_LOCUS (s),
701 if (TREE_OPERAND (s, 0) != NULL_TREE)
703 if (TREE_CODE (TREE_OPERAND (s, 0)) == MODIFY_EXPR)
704 mf_xform_derefs_1 (&i, &TREE_OPERAND (TREE_OPERAND (s, 0), 1), EXPR_LOCUS (s),
707 mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
718 /* ------------------------------------------------------------------------ */
719 /* ADDR_EXPR transform */
722 /* This struct is passed between mf_xform_decls to store state needed
723 during the traversal searching for objects that have their
725 struct mf_xform_decls_data
731 /* Synthesize a CALL_EXPR and a TRY_FINALLY_EXPR, for this chain of
732 _DECLs if appropriate. Arrange to call the __mf_register function
733 now, and the __mf_unregister function later for each. */
735 mx_register_decls (tree decl, tree *stmt_list)
737 tree finally_stmts = NULL_TREE;
738 tree_stmt_iterator initially_stmts = tsi_start (*stmt_list);
740 while (decl != NULL_TREE)
743 if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) &&
744 (! TREE_STATIC (decl)) && /* auto variable */
745 (! DECL_EXTERNAL (decl)) && /* not extern variable */
746 (TREE_TYPE (decl) != error_mark_node) && /* not decl with error */
747 (COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl))) && /* complete type */
748 (! mf_marked_p (decl)) && /* not already processed */
749 (TREE_ADDRESSABLE (decl))) /* has address taken */
751 tree size = NULL_TREE, variable_name;
752 tree unregister_fncall, unregister_fncall_params;
753 tree register_fncall, register_fncall_params;
755 if (DECL_DEFER_OUTPUT (decl))
757 /* Oh no ... it's probably a variable-length array (VLA).
758 The size and address cannot be computed by merely
759 looking at the DECL. See gimplfiy_decl_stmt for the
760 method by which VLA declarations turn into calls to
761 BUILT_IN_STACK_ALLOC. We assume that multiple
762 VLAs declared later in the same block get allocation
763 code later than the others. */
764 tree stack_alloc_call = NULL_TREE;
766 while(! tsi_end_p (initially_stmts))
768 tree t = tsi_stmt (initially_stmts);
770 tree call = NULL_TREE;
771 if (TREE_CODE (t) == CALL_EXPR)
773 else if (TREE_CODE (t) == MODIFY_EXPR &&
774 TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR)
775 call = TREE_OPERAND (t, 1);
776 else if (TREE_CODE (t) == TRY_FINALLY_EXPR)
778 /* We hope that this is the try/finally block sometimes
779 constructed by gimplify_bind_expr() for a BIND_EXPR
780 that contains VLAs. This very naive recursion
781 appears to be sufficient. */
782 initially_stmts = tsi_start (TREE_OPERAND (t, 0));
785 if (call != NULL_TREE)
787 if (TREE_CODE (TREE_OPERAND(call, 0)) == ADDR_EXPR &&
788 TREE_OPERAND (TREE_OPERAND (call, 0), 0) ==
789 implicit_built_in_decls [BUILT_IN_STACK_ALLOC])
791 tree stack_alloc_args = TREE_OPERAND (call, 1);
792 tree stack_alloc_op1 = TREE_VALUE (stack_alloc_args);
793 tree stack_alloc_op2 = TREE_VALUE (TREE_CHAIN (stack_alloc_args));
795 if (TREE_CODE (stack_alloc_op1) == ADDR_EXPR &&
796 TREE_OPERAND (stack_alloc_op1, 0) == decl)
799 size = stack_alloc_op2;
800 stack_alloc_call = call;
801 /* Advance iterator to point past this allocation call. */
802 tsi_next (&initially_stmts);
808 tsi_next (&initially_stmts);
811 if (stack_alloc_call == NULL_TREE)
813 warning ("mudflap cannot handle variable-sized declaration `%s'",
814 IDENTIFIER_POINTER (DECL_NAME (decl)));
820 size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl)));
823 /* (& VARIABLE, sizeof (VARIABLE)) */
824 unregister_fncall_params =
825 tree_cons (NULL_TREE,
826 convert (ptr_type_node,
827 mf_mark (build1 (ADDR_EXPR,
828 build_pointer_type (TREE_TYPE (decl)),
830 tree_cons (NULL_TREE, size, NULL_TREE));
831 /* __mf_unregister (...) */
832 unregister_fncall = build_function_call_expr (mf_unregister_fndecl,
833 unregister_fncall_params);
835 /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */
836 variable_name = mf_varname_tree (decl);
837 register_fncall_params =
838 tree_cons (NULL_TREE,
839 convert (ptr_type_node,
840 mf_mark (build1 (ADDR_EXPR,
841 build_pointer_type (TREE_TYPE (decl)),
843 tree_cons (NULL_TREE,
845 tree_cons (NULL_TREE,
846 build_int_2 (3, 0), /* __MF_TYPE_STACK */
847 tree_cons (NULL_TREE,
851 /* __mf_register (...) */
852 register_fncall = build_function_call_expr (mf_register_fndecl,
853 register_fncall_params);
855 /* Accumulate the two calls. */
856 /* ??? Set EXPR_LOCUS. */
857 gimplify_stmt (®ister_fncall);
858 gimplify_stmt (&unregister_fncall);
860 /* Add the __mf_register call at the current appending point. */
861 if (tsi_end_p (initially_stmts))
862 internal_error ("mudflap ran off end of BIND_EXPR body");
863 tsi_link_before (& initially_stmts, register_fncall, TSI_SAME_STMT);
865 /* Accumulate the FINALLY piece. */
866 append_to_statement_list (unregister_fncall, &finally_stmts);
871 decl = TREE_CHAIN (decl);
874 /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */
875 if (finally_stmts != NULL_TREE)
877 tree t = build (TRY_FINALLY_EXPR, void_type_node,
878 *stmt_list, finally_stmts);
880 append_to_statement_list (t, stmt_list);
885 /* Process every variable mentioned in BIND_EXPRs. */
887 mx_xfn_xform_decls (tree *t, int *continue_p, void *data)
889 struct mf_xform_decls_data* d = (struct mf_xform_decls_data*) data;
891 if (*t == NULL_TREE || *t == error_mark_node)
899 switch (TREE_CODE (*t))
903 /* Process function parameters now (but only once). */
904 mx_register_decls (d->param_decls, &BIND_EXPR_BODY (*t));
905 d->param_decls = NULL_TREE;
907 mx_register_decls (BIND_EXPR_VARS (*t), &BIND_EXPR_BODY (*t));
918 /* Perform the object lifetime tracking mudflap transform on the given function
919 tree. The tree is mutated in place, with possibly copied subtree nodes.
921 For every auto variable declared, if its address is ever taken
922 within the function, then supply its lifetime to the mudflap
923 runtime with the __mf_register and __mf_unregister calls.
927 mf_xform_decls (tree fnbody, tree fnparams)
929 struct mf_xform_decls_data d;
930 d.param_decls = fnparams;
931 walk_tree_without_duplicates (&fnbody, mx_xfn_xform_decls, &d);
935 /* ------------------------------------------------------------------------ */
938 /* Remember given node as a static of some kind: global data,
939 function-scope static, or an anonymous constant. Its assembler
944 /* A list of globals whose incomplete declarations we encountered.
945 Instead of emitting the __mf_register call for them here, it's
946 delayed until program finish time. If they're still incomplete by
947 then, warnings are emitted. */
949 static GTY (()) varray_type deferred_static_decls;
951 /* A list of statements for calling __mf_register() at startup time. */
952 static GTY (()) tree enqueued_call_stmt_chain;
955 mudflap_register_call (tree obj, tree object_size, tree varname)
957 tree arg, args, call_stmt;
959 args = tree_cons (NULL_TREE, varname, NULL_TREE);
961 arg = build_int_2 (4, 0); /* __MF_TYPE_STATIC */
962 args = tree_cons (NULL_TREE, arg, args);
964 arg = convert (size_type_node, object_size);
965 args = tree_cons (NULL_TREE, arg, args);
967 arg = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (obj)), obj);
968 arg = convert (ptr_type_node, arg);
969 args = tree_cons (NULL_TREE, arg, args);
971 mf_init_extern_trees ();
972 call_stmt = build_function_call_expr (mf_register_fndecl, args);
974 append_to_statement_list (call_stmt, &enqueued_call_stmt_chain);
978 mudflap_enqueue_decl (tree obj)
980 if (mf_marked_p (obj))
983 /* We don't need to process variable decls that are internally
984 generated extern. If we did, we'd end up with warnings for them
985 during mudflap_finish_file (). That would confuse the user,
986 since the text would refer to variables that don't show up in the
987 user's source code. */
988 if (DECL_P (obj) && DECL_EXTERNAL (obj) && DECL_ARTIFICIAL (obj))
991 if (COMPLETE_TYPE_P (TREE_TYPE (obj)))
997 object_size = size_in_bytes (TREE_TYPE (obj));
1001 fprintf (dump_file, "enqueue_decl obj=`");
1002 print_generic_expr (dump_file, obj, dump_flags);
1003 fprintf (dump_file, "' size=");
1004 print_generic_expr (dump_file, object_size, dump_flags);
1005 fprintf (dump_file, "\n");
1008 /* NB: the above condition doesn't require TREE_USED or
1009 TREE_ADDRESSABLE. That's because this object may be a global
1010 only used from other compilation units. XXX: Maybe static
1011 objects could require those attributes being set. */
1013 mudflap_register_call (obj, object_size, mf_varname_tree (obj));
1019 if (! deferred_static_decls)
1020 VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list");
1022 /* Ugh, linear search... */
1023 for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1024 if (VARRAY_TREE (deferred_static_decls, i) == obj)
1026 warning ("mudflap cannot track lifetime of `%s'",
1027 IDENTIFIER_POINTER (DECL_NAME (obj)));
1031 VARRAY_PUSH_TREE (deferred_static_decls, obj);
1036 mudflap_enqueue_constant (tree obj)
1038 tree object_size, varname;
1040 if (mf_marked_p (obj))
1043 if (TREE_CODE (obj) == STRING_CST)
1044 object_size = build_int_2 (TREE_STRING_LENGTH (obj), 0);
1046 object_size = size_in_bytes (TREE_TYPE (obj));
1050 fprintf (dump_file, "enqueue_constant obj=`");
1051 print_generic_expr (dump_file, obj, dump_flags);
1052 fprintf (dump_file, "' size=");
1053 print_generic_expr (dump_file, object_size, dump_flags);
1054 fprintf (dump_file, "\n");
1057 if (TREE_CODE (obj) == STRING_CST)
1058 varname = mf_build_string ("string literal");
1060 varname = mf_build_string ("constant");
1062 mudflap_register_call (obj, object_size, varname);
1067 /* Emit any file-wide instrumentation. */
1069 mudflap_finish_file (void)
1071 /* Try to give the deferred objects one final try. */
1072 if (deferred_static_decls)
1076 for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1078 tree obj = VARRAY_TREE (deferred_static_decls, i);
1080 /* Call enqueue_decl again on the same object it has previously
1081 put into the table. (It won't modify the table this time, so
1082 infinite iteration is not a problem.) */
1083 mudflap_enqueue_decl (obj);
1086 VARRAY_CLEAR (deferred_static_decls);
1089 mflang_flush_calls (enqueued_call_stmt_chain);
1094 #include "gt-tree-mudflap.h"