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 (COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl
))) && /* complete type */
747 (! mf_marked_p (decl
)) && /* not already processed */
748 (TREE_ADDRESSABLE (decl
))) /* has address taken */
750 tree size
= NULL_TREE
, variable_name
;
751 tree unregister_fncall
, unregister_fncall_params
;
752 tree register_fncall
, register_fncall_params
;
754 if (DECL_DEFER_OUTPUT (decl
))
756 /* Oh no ... it's probably a variable-length array (VLA).
757 The size and address cannot be computed by merely
758 looking at the DECL. See gimplfiy_decl_stmt for the
759 method by which VLA declarations turn into calls to
760 BUILT_IN_STACK_ALLOC. We assume that multiple
761 VLAs declared later in the same block get allocation
762 code later than the others. */
763 tree stack_alloc_call
= NULL_TREE
;
765 while(! tsi_end_p (initially_stmts
))
767 tree t
= tsi_stmt (initially_stmts
);
769 tree call
= NULL_TREE
;
770 if (TREE_CODE (t
) == CALL_EXPR
)
772 else if (TREE_CODE (t
) == MODIFY_EXPR
&&
773 TREE_CODE (TREE_OPERAND (t
, 1)) == CALL_EXPR
)
774 call
= TREE_OPERAND (t
, 1);
775 else if (TREE_CODE (t
) == TRY_FINALLY_EXPR
)
777 /* We hope that this is the try/finally block sometimes
778 constructed by gimplify_bind_expr() for a BIND_EXPR
779 that contains VLAs. This very naive recursion
780 appears to be sufficient. */
781 initially_stmts
= tsi_start (TREE_OPERAND (t
, 0));
784 if (call
!= NULL_TREE
)
786 if (TREE_CODE (TREE_OPERAND(call
, 0)) == ADDR_EXPR
&&
787 TREE_OPERAND (TREE_OPERAND (call
, 0), 0) ==
788 implicit_built_in_decls
[BUILT_IN_STACK_ALLOC
])
790 tree stack_alloc_args
= TREE_OPERAND (call
, 1);
791 tree stack_alloc_op1
= TREE_VALUE (stack_alloc_args
);
792 tree stack_alloc_op2
= TREE_VALUE (TREE_CHAIN (stack_alloc_args
));
794 if (TREE_CODE (stack_alloc_op1
) == ADDR_EXPR
&&
795 TREE_OPERAND (stack_alloc_op1
, 0) == decl
)
798 size
= stack_alloc_op2
;
799 stack_alloc_call
= call
;
800 /* Advance iterator to point past this allocation call. */
801 tsi_next (&initially_stmts
);
807 tsi_next (&initially_stmts
);
810 if (stack_alloc_call
== NULL_TREE
)
812 warning ("mudflap cannot handle variable-sized declaration `%s'",
813 IDENTIFIER_POINTER (DECL_NAME (decl
)));
819 size
= convert (size_type_node
, TYPE_SIZE_UNIT (TREE_TYPE (decl
)));
822 /* (& VARIABLE, sizeof (VARIABLE)) */
823 unregister_fncall_params
=
824 tree_cons (NULL_TREE
,
825 convert (ptr_type_node
,
826 mf_mark (build1 (ADDR_EXPR
,
827 build_pointer_type (TREE_TYPE (decl
)),
829 tree_cons (NULL_TREE
, size
, NULL_TREE
));
830 /* __mf_unregister (...) */
831 unregister_fncall
= build_function_call_expr (mf_unregister_fndecl
,
832 unregister_fncall_params
);
834 /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */
835 variable_name
= mf_varname_tree (decl
);
836 register_fncall_params
=
837 tree_cons (NULL_TREE
,
838 convert (ptr_type_node
,
839 mf_mark (build1 (ADDR_EXPR
,
840 build_pointer_type (TREE_TYPE (decl
)),
842 tree_cons (NULL_TREE
,
844 tree_cons (NULL_TREE
,
845 build_int_2 (3, 0), /* __MF_TYPE_STACK */
846 tree_cons (NULL_TREE
,
850 /* __mf_register (...) */
851 register_fncall
= build_function_call_expr (mf_register_fndecl
,
852 register_fncall_params
);
854 /* Accumulate the two calls. */
855 /* ??? Set EXPR_LOCUS. */
856 gimplify_stmt (®ister_fncall
);
857 gimplify_stmt (&unregister_fncall
);
859 /* Add the __mf_register call at the current appending point. */
860 if (tsi_end_p (initially_stmts
))
861 internal_error ("mudflap ran off end of BIND_EXPR body");
862 tsi_link_before (& initially_stmts
, register_fncall
, TSI_SAME_STMT
);
864 /* Accumulate the FINALLY piece. */
865 append_to_statement_list (unregister_fncall
, &finally_stmts
);
870 decl
= TREE_CHAIN (decl
);
873 /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */
874 if (finally_stmts
!= NULL_TREE
)
876 tree t
= build (TRY_FINALLY_EXPR
, void_type_node
,
877 *stmt_list
, finally_stmts
);
879 append_to_statement_list (t
, stmt_list
);
884 /* Process every variable mentioned in BIND_EXPRs. */
886 mx_xfn_xform_decls (tree
*t
, int *continue_p
, void *data
)
888 struct mf_xform_decls_data
* d
= (struct mf_xform_decls_data
*) data
;
890 if (*t
== NULL_TREE
|| *t
== error_mark_node
)
898 switch (TREE_CODE (*t
))
902 /* Process function parameters now (but only once). */
903 mx_register_decls (d
->param_decls
, &BIND_EXPR_BODY (*t
));
904 d
->param_decls
= NULL_TREE
;
906 mx_register_decls (BIND_EXPR_VARS (*t
), &BIND_EXPR_BODY (*t
));
917 /* Perform the object lifetime tracking mudflap transform on the given function
918 tree. The tree is mutated in place, with possibly copied subtree nodes.
920 For every auto variable declared, if its address is ever taken
921 within the function, then supply its lifetime to the mudflap
922 runtime with the __mf_register and __mf_unregister calls.
926 mf_xform_decls (tree fnbody
, tree fnparams
)
928 struct mf_xform_decls_data d
;
929 d
.param_decls
= fnparams
;
930 walk_tree_without_duplicates (&fnbody
, mx_xfn_xform_decls
, &d
);
934 /* ------------------------------------------------------------------------ */
937 /* Remember given node as a static of some kind: global data,
938 function-scope static, or an anonymous constant. Its assembler
943 /* A list of globals whose incomplete declarations we encountered.
944 Instead of emitting the __mf_register call for them here, it's
945 delayed until program finish time. If they're still incomplete by
946 then, warnings are emitted. */
948 static GTY (()) varray_type deferred_static_decls
;
950 /* A list of statements for calling __mf_register() at startup time. */
951 static GTY (()) tree enqueued_call_stmt_chain
;
954 mudflap_register_call (tree obj
, tree object_size
, tree varname
)
956 tree arg
, args
, call_stmt
;
958 args
= tree_cons (NULL_TREE
, varname
, NULL_TREE
);
960 arg
= build_int_2 (4, 0); /* __MF_TYPE_STATIC */
961 args
= tree_cons (NULL_TREE
, arg
, args
);
963 arg
= convert (size_type_node
, object_size
);
964 args
= tree_cons (NULL_TREE
, arg
, args
);
966 arg
= build1 (ADDR_EXPR
, build_pointer_type (TREE_TYPE (obj
)), obj
);
967 arg
= convert (ptr_type_node
, arg
);
968 args
= tree_cons (NULL_TREE
, arg
, args
);
970 mf_init_extern_trees ();
971 call_stmt
= build_function_call_expr (mf_register_fndecl
, args
);
973 append_to_statement_list (call_stmt
, &enqueued_call_stmt_chain
);
977 mudflap_enqueue_decl (tree obj
)
979 if (mf_marked_p (obj
))
982 /* We don't need to process variable decls that are internally
983 generated extern. If we did, we'd end up with warnings for them
984 during mudflap_finish_file (). That would confuse the user,
985 since the text would refer to variables that don't show up in the
986 user's source code. */
987 if (DECL_P (obj
) && DECL_EXTERNAL (obj
) && DECL_ARTIFICIAL (obj
))
990 if (COMPLETE_TYPE_P (TREE_TYPE (obj
)))
996 object_size
= size_in_bytes (TREE_TYPE (obj
));
1000 fprintf (dump_file
, "enqueue_decl obj=`");
1001 print_generic_expr (dump_file
, obj
, dump_flags
);
1002 fprintf (dump_file
, "' size=");
1003 print_generic_expr (dump_file
, object_size
, dump_flags
);
1004 fprintf (dump_file
, "\n");
1007 /* NB: the above condition doesn't require TREE_USED or
1008 TREE_ADDRESSABLE. That's because this object may be a global
1009 only used from other compilation units. XXX: Maybe static
1010 objects could require those attributes being set. */
1012 mudflap_register_call (obj
, object_size
, mf_varname_tree (obj
));
1018 if (! deferred_static_decls
)
1019 VARRAY_TREE_INIT (deferred_static_decls
, 10, "deferred static list");
1021 /* Ugh, linear search... */
1022 for (i
= 0; i
< VARRAY_ACTIVE_SIZE (deferred_static_decls
); i
++)
1023 if (VARRAY_TREE (deferred_static_decls
, i
) == obj
)
1025 warning ("mudflap cannot track lifetime of `%s'",
1026 IDENTIFIER_POINTER (DECL_NAME (obj
)));
1030 VARRAY_PUSH_TREE (deferred_static_decls
, obj
);
1035 mudflap_enqueue_constant (tree obj
)
1037 tree object_size
, varname
;
1039 if (mf_marked_p (obj
))
1042 if (TREE_CODE (obj
) == STRING_CST
)
1043 object_size
= build_int_2 (TREE_STRING_LENGTH (obj
), 0);
1045 object_size
= size_in_bytes (TREE_TYPE (obj
));
1049 fprintf (dump_file
, "enqueue_constant obj=`");
1050 print_generic_expr (dump_file
, obj
, dump_flags
);
1051 fprintf (dump_file
, "' size=");
1052 print_generic_expr (dump_file
, object_size
, dump_flags
);
1053 fprintf (dump_file
, "\n");
1056 if (TREE_CODE (obj
) == STRING_CST
)
1057 varname
= mf_build_string ("string literal");
1059 varname
= mf_build_string ("constant");
1061 mudflap_register_call (obj
, object_size
, varname
);
1066 /* Emit any file-wide instrumentation. */
1068 mudflap_finish_file (void)
1070 /* Try to give the deferred objects one final try. */
1071 if (deferred_static_decls
)
1075 for (i
= 0; i
< VARRAY_ACTIVE_SIZE (deferred_static_decls
); i
++)
1077 tree obj
= VARRAY_TREE (deferred_static_decls
, i
);
1079 /* Call enqueue_decl again on the same object it has previously
1080 put into the table. (It won't modify the table this time, so
1081 infinite iteration is not a problem.) */
1082 mudflap_enqueue_decl (obj
);
1085 VARRAY_CLEAR (deferred_static_decls
);
1088 mflang_flush_calls (enqueued_call_stmt_chain
);
1093 #include "gt-tree-mudflap.h"