2005-01-20 Michael Koch <konqueror@gmx.de>
[official-gcc.git] / gcc / tree-mudflap.c
blob8a57efbe67673667a7582388422e73721f8bfc94
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
11 version.
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
16 for more details.
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
21 02111-1307, USA. */
24 #include "config.h"
25 #include "errors.h"
26 #include "system.h"
27 #include "coretypes.h"
28 #include "tm.h"
29 #include "tree.h"
30 #include "flags.h"
31 #include "function.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"
38 #include "hashtab.h"
39 #include "diagnostic.h"
40 #include <demangle.h>
41 #include "langhooks.h"
42 #include "ggc.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
63 transforms. */
64 tree
65 mf_mark (tree t)
67 void **slot;
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);
73 *slot = t;
74 return t;
78 int
79 mf_marked_p (tree t)
81 void *entry;
83 if (marked_trees == NULL)
84 return 0;
86 entry = htab_find (marked_trees, t);
87 return (entry != NULL);
90 static tree
91 mf_build_string (const char *string)
93 size_t len = strlen (string);
94 tree result = mf_mark (build_string (len + 1, string));
96 TREE_TYPE (result)
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. */
112 static void
113 mudflap_function_decls (void)
115 if (mf_marked_p (current_function_decl))
116 return;
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);
127 static bool
128 gate_mudflap (void)
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 */
138 NULL, /* sub */
139 NULL, /* next */
140 0, /* static_pass_number */
141 0, /* tv_id */
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. */
152 static void
153 mudflap_function_ops (void)
155 if (mf_marked_p (current_function_decl))
156 return;
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 */
177 NULL, /* sub */
178 NULL, /* next */
179 0, /* static_pass_number */
180 0, /* tv_id */
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
231 declarations. */
232 static void
233 mf_init_extern_trees (void)
235 static bool done = false;
237 if (done)
238 return;
239 done = true;
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. */
258 static void
259 mf_decl_cache_locals (tree* body)
261 tree_stmt_iterator i = tsi_start (*body);
262 tree t;
264 mf_cache_shift_decl_l
265 = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_shift_decl),
266 "__mf_lookup_shift_l"));
268 mf_cache_mask_decl_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));
276 gimplify_stmt (&t);
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));
282 gimplify_stmt (&t);
283 tsi_link_before (&i, t, TSI_NEW_STMT);
287 static void
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
298 name. */
300 static tree
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;
307 tree result;
309 if (decl == NULL_TREE)
310 abort ();
312 if (!initialized)
314 pp_construct (buf, /* prefix */ NULL, /* line-width */ 0);
315 initialized = 1;
317 pp_clear_output_area (buf);
319 /* Add FILENAME[:LINENUMBER]. */
321 const char *sourcefile;
322 unsigned sourceline;
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);
333 if (sourceline != 0)
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, ") ");
355 else
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);
385 return result;
389 /* And another friend, for producing a simpler message. */
391 static tree
392 mf_file_function_line_tree (location_t *locus)
394 const char *file = NULL, *colon, *line, *op, *name, *cp;
395 char linebuf[18];
396 char *string;
397 tree result;
399 /* Add FILENAME. */
400 if (locus != NULL)
401 file = locus->file;
402 if (file == NULL && current_function_decl != NULL_TREE)
403 file = DECL_SOURCE_FILE (current_function_decl);
404 if (file == NULL)
405 file = "<unknown file>";
407 /* Add :LINENUMBER. */
408 if (locus != NULL && locus->line > 0)
410 sprintf (linebuf, "%d", locus->line);
411 colon = ":";
412 line = linebuf;
414 else
415 colon = line = "";
417 /* Add (FUNCTION). */
418 name = lang_hooks.decl_printable_name (current_function_decl, 1);
419 if (name)
421 op = " (";
422 cp = ")";
424 else
425 op = name = cp = "";
427 string = concat (file, colon, line, op, name, cp, NULL);
428 result = mf_build_string (string);
429 free (string);
431 return result;
435 static void
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;
441 tree mf_value;
442 tree mf_base;
443 tree mf_elem;
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);
452 if (locus != NULL)
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));
460 if (locus != NULL)
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)
466 & __mf_mask]. */
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);
476 if (locus != NULL)
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),
486 __mf_check ();
487 ... and only if single-threaded:
488 __mf_lookup_shift_1 = f...;
489 __mf_lookup_mask_l = ...;
493 /* __mf_elem->low */
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. */
520 stmt = NULL;
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 ());
541 if (locus != NULL)
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);
548 static void
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)
556 return;
558 t = *tp;
559 type = TREE_TYPE (t);
560 size = TYPE_SIZE_UNIT (type);
562 switch (TREE_CODE (t))
564 case ARRAY_REF:
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. */
569 tree op0, op1;
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. */
578 if (!dom)
579 break;
580 if (!TYPE_MIN_VALUE (dom) || !really_constant_p (TYPE_MIN_VALUE (dom)))
581 break;
582 if (!TYPE_MAX_VALUE (dom) || !really_constant_p (TYPE_MAX_VALUE (dom)))
583 break;
584 if (tree_int_cst_lt (op1, TYPE_MIN_VALUE (dom))
585 || tree_int_cst_lt (TYPE_MAX_VALUE (dom), op1))
586 break;
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))
591 return;
593 /* Only continue if we're still looking at an array. */
594 if (TREE_CODE (op0) != ARRAY_REF)
595 break;
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);
605 break;
607 case INDIRECT_REF:
608 addr = TREE_OPERAND (t, 0);
609 ptr_type = TREE_TYPE (addr);
610 break;
612 case ARRAY_RANGE_REF:
613 warning ("mudflap checking not yet implemented for ARRAY_RANGE_REF");
614 return;
616 case COMPONENT_REF:
618 tree field;
620 /* If we're not dereferencing something, then the access
621 must be ok. */
622 if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
623 return;
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)));
641 else
643 ptr_type = build_pointer_type (type);
644 addr = build1 (ADDR_EXPR, ptr_type, t);
647 break;
649 case BIT_FIELD_REF:
651 tree ofs, rem, bpu;
653 /* If we're not dereferencing something, then the access
654 must be ok. */
655 if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
656 return;
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));
672 break;
674 default:
675 return;
678 mf_build_check_statement_for (addr, size, iter, locus, dirflag);
681 static void
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),
695 integer_one_node);
696 mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 1), EXPR_LOCUS (s),
697 integer_zero_node);
698 break;
700 case RETURN_EXPR:
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),
705 integer_zero_node);
706 else
707 mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
708 integer_zero_node);
710 break;
712 default:
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
724 addresses taken. */
725 struct mf_xform_decls_data
727 tree param_decls;
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. */
734 static void
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)
742 /* Eligible decl? */
743 if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
744 /* It must be a non-external, automatic variable. */
745 && ! DECL_EXTERNAL (decl)
746 && ! TREE_STATIC (decl)
747 /* The decl must have its address taken. */
748 && TREE_ADDRESSABLE (decl)
749 /* The type of the variable must be complete. */
750 && COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl))
751 /* Don't process the same decl twice. */
752 && ! mf_marked_p (decl))
754 tree size = NULL_TREE, variable_name;
755 tree unregister_fncall, unregister_fncall_params;
756 tree register_fncall, register_fncall_params;
758 if (DECL_DEFER_OUTPUT (decl))
760 /* Oh no ... it's probably a variable-length array (VLA).
761 The size and address cannot be computed by merely
762 looking at the DECL. See gimplfiy_decl_stmt for the
763 method by which VLA declarations turn into calls to
764 BUILT_IN_STACK_ALLOC. We assume that multiple
765 VLAs declared later in the same block get allocation
766 code later than the others. */
767 tree stack_alloc_call = NULL_TREE;
769 while(! tsi_end_p (initially_stmts))
771 tree t = tsi_stmt (initially_stmts);
773 tree call = NULL_TREE;
774 if (TREE_CODE (t) == CALL_EXPR)
775 call = t;
776 else if (TREE_CODE (t) == MODIFY_EXPR &&
777 TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR)
778 call = TREE_OPERAND (t, 1);
779 else if (TREE_CODE (t) == TRY_FINALLY_EXPR)
781 /* We hope that this is the try/finally block sometimes
782 constructed by gimplify_bind_expr() for a BIND_EXPR
783 that contains VLAs. This very naive recursion
784 appears to be sufficient. */
785 initially_stmts = tsi_start (TREE_OPERAND (t, 0));
788 if (call != NULL_TREE)
790 if (TREE_CODE (TREE_OPERAND(call, 0)) == ADDR_EXPR &&
791 TREE_OPERAND (TREE_OPERAND (call, 0), 0) ==
792 implicit_built_in_decls [BUILT_IN_STACK_ALLOC])
794 tree stack_alloc_args = TREE_OPERAND (call, 1);
795 tree stack_alloc_op1 = TREE_VALUE (stack_alloc_args);
796 tree stack_alloc_op2 = TREE_VALUE (TREE_CHAIN (stack_alloc_args));
798 if (TREE_CODE (stack_alloc_op1) == ADDR_EXPR &&
799 TREE_OPERAND (stack_alloc_op1, 0) == decl)
801 /* Got it! */
802 size = stack_alloc_op2;
803 stack_alloc_call = call;
804 /* Advance iterator to point past this allocation call. */
805 tsi_next (&initially_stmts);
806 break;
811 tsi_next (&initially_stmts);
814 if (stack_alloc_call == NULL_TREE)
816 warning ("mudflap cannot handle variable-sized declaration `%s'",
817 IDENTIFIER_POINTER (DECL_NAME (decl)));
818 break;
821 else
823 size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl)));
826 /* (& VARIABLE, sizeof (VARIABLE)) */
827 unregister_fncall_params =
828 tree_cons (NULL_TREE,
829 convert (ptr_type_node,
830 mf_mark (build1 (ADDR_EXPR,
831 build_pointer_type (TREE_TYPE (decl)),
832 decl))),
833 tree_cons (NULL_TREE, size, NULL_TREE));
834 /* __mf_unregister (...) */
835 unregister_fncall = build_function_call_expr (mf_unregister_fndecl,
836 unregister_fncall_params);
838 /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */
839 variable_name = mf_varname_tree (decl);
840 register_fncall_params =
841 tree_cons (NULL_TREE,
842 convert (ptr_type_node,
843 mf_mark (build1 (ADDR_EXPR,
844 build_pointer_type (TREE_TYPE (decl)),
845 decl))),
846 tree_cons (NULL_TREE,
847 size,
848 tree_cons (NULL_TREE,
849 build_int_2 (3, 0), /* __MF_TYPE_STACK */
850 tree_cons (NULL_TREE,
851 variable_name,
852 NULL_TREE))));
854 /* __mf_register (...) */
855 register_fncall = build_function_call_expr (mf_register_fndecl,
856 register_fncall_params);
858 /* Accumulate the two calls. */
859 /* ??? Set EXPR_LOCUS. */
860 gimplify_stmt (&register_fncall);
861 gimplify_stmt (&unregister_fncall);
863 /* Add the __mf_register call at the current appending point. */
864 if (tsi_end_p (initially_stmts))
865 internal_error ("mudflap ran off end of BIND_EXPR body");
866 tsi_link_before (&initially_stmts, register_fncall, TSI_SAME_STMT);
868 /* Accumulate the FINALLY piece. */
869 append_to_statement_list (unregister_fncall, &finally_stmts);
871 mf_mark (decl);
874 decl = TREE_CHAIN (decl);
877 /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */
878 if (finally_stmts != NULL_TREE)
880 tree t = build (TRY_FINALLY_EXPR, void_type_node,
881 *stmt_list, finally_stmts);
882 *stmt_list = NULL;
883 append_to_statement_list (t, stmt_list);
888 /* Process every variable mentioned in BIND_EXPRs. */
889 static tree
890 mx_xfn_xform_decls (tree *t, int *continue_p, void *data)
892 struct mf_xform_decls_data* d = (struct mf_xform_decls_data*) data;
894 if (*t == NULL_TREE || *t == error_mark_node)
896 *continue_p = 0;
897 return NULL_TREE;
900 *continue_p = 1;
902 switch (TREE_CODE (*t))
904 case BIND_EXPR:
906 /* Process function parameters now (but only once). */
907 mx_register_decls (d->param_decls, &BIND_EXPR_BODY (*t));
908 d->param_decls = NULL_TREE;
910 mx_register_decls (BIND_EXPR_VARS (*t), &BIND_EXPR_BODY (*t));
912 break;
914 default:
915 break;
918 return NULL;
921 /* Perform the object lifetime tracking mudflap transform on the given function
922 tree. The tree is mutated in place, with possibly copied subtree nodes.
924 For every auto variable declared, if its address is ever taken
925 within the function, then supply its lifetime to the mudflap
926 runtime with the __mf_register and __mf_unregister calls.
929 static void
930 mf_xform_decls (tree fnbody, tree fnparams)
932 struct mf_xform_decls_data d;
933 d.param_decls = fnparams;
934 walk_tree_without_duplicates (&fnbody, mx_xfn_xform_decls, &d);
938 /* ------------------------------------------------------------------------ */
941 /* Remember given node as a static of some kind: global data,
942 function-scope static, or an anonymous constant. Its assembler
943 label is given.
947 /* A list of globals whose incomplete declarations we encountered.
948 Instead of emitting the __mf_register call for them here, it's
949 delayed until program finish time. If they're still incomplete by
950 then, warnings are emitted. */
952 static GTY (()) varray_type deferred_static_decls;
954 /* A list of statements for calling __mf_register() at startup time. */
955 static GTY (()) tree enqueued_call_stmt_chain;
957 static void
958 mudflap_register_call (tree obj, tree object_size, tree varname)
960 tree arg, args, call_stmt;
962 args = tree_cons (NULL_TREE, varname, NULL_TREE);
964 arg = build_int_2 (4, 0); /* __MF_TYPE_STATIC */
965 args = tree_cons (NULL_TREE, arg, args);
967 arg = convert (size_type_node, object_size);
968 args = tree_cons (NULL_TREE, arg, args);
970 arg = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (obj)), obj);
971 arg = convert (ptr_type_node, arg);
972 args = tree_cons (NULL_TREE, arg, args);
974 mf_init_extern_trees ();
975 call_stmt = build_function_call_expr (mf_register_fndecl, args);
977 append_to_statement_list (call_stmt, &enqueued_call_stmt_chain);
980 void
981 mudflap_enqueue_decl (tree obj)
983 if (mf_marked_p (obj))
984 return;
986 /* We don't need to process variable decls that are internally
987 generated extern. If we did, we'd end up with warnings for them
988 during mudflap_finish_file (). That would confuse the user,
989 since the text would refer to variables that don't show up in the
990 user's source code. */
991 if (DECL_P (obj) && DECL_EXTERNAL (obj) && DECL_ARTIFICIAL (obj))
992 return;
994 if (COMPLETE_TYPE_P (TREE_TYPE (obj)))
996 tree object_size;
998 mf_mark (obj);
1000 object_size = size_in_bytes (TREE_TYPE (obj));
1002 if (dump_file)
1004 fprintf (dump_file, "enqueue_decl obj=`");
1005 print_generic_expr (dump_file, obj, dump_flags);
1006 fprintf (dump_file, "' size=");
1007 print_generic_expr (dump_file, object_size, dump_flags);
1008 fprintf (dump_file, "\n");
1011 /* NB: the above condition doesn't require TREE_USED or
1012 TREE_ADDRESSABLE. That's because this object may be a global
1013 only used from other compilation units. XXX: Maybe static
1014 objects could require those attributes being set. */
1016 mudflap_register_call (obj, object_size, mf_varname_tree (obj));
1018 else
1020 size_t i;
1022 if (! deferred_static_decls)
1023 VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list");
1025 /* Ugh, linear search... */
1026 for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1027 if (VARRAY_TREE (deferred_static_decls, i) == obj)
1029 warning ("mudflap cannot track lifetime of `%s'",
1030 IDENTIFIER_POINTER (DECL_NAME (obj)));
1031 return;
1034 VARRAY_PUSH_TREE (deferred_static_decls, obj);
1038 void
1039 mudflap_enqueue_constant (tree obj)
1041 tree object_size, varname;
1043 if (mf_marked_p (obj))
1044 return;
1046 if (TREE_CODE (obj) == STRING_CST)
1047 object_size = build_int_2 (TREE_STRING_LENGTH (obj), 0);
1048 else
1049 object_size = size_in_bytes (TREE_TYPE (obj));
1051 if (dump_file)
1053 fprintf (dump_file, "enqueue_constant obj=`");
1054 print_generic_expr (dump_file, obj, dump_flags);
1055 fprintf (dump_file, "' size=");
1056 print_generic_expr (dump_file, object_size, dump_flags);
1057 fprintf (dump_file, "\n");
1060 if (TREE_CODE (obj) == STRING_CST)
1061 varname = mf_build_string ("string literal");
1062 else
1063 varname = mf_build_string ("constant");
1065 mudflap_register_call (obj, object_size, varname);
1070 /* Emit any file-wide instrumentation. */
1071 void
1072 mudflap_finish_file (void)
1074 /* Try to give the deferred objects one final try. */
1075 if (deferred_static_decls)
1077 size_t i;
1079 for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1081 tree obj = VARRAY_TREE (deferred_static_decls, i);
1083 /* Call enqueue_decl again on the same object it has previously
1084 put into the table. (It won't modify the table this time, so
1085 infinite iteration is not a problem.) */
1086 mudflap_enqueue_decl (obj);
1089 VARRAY_CLEAR (deferred_static_decls);
1092 mflang_flush_calls (enqueued_call_stmt_chain);
1097 #include "gt-tree-mudflap.h"