* gnu/regexp/CharIndexedReader.java: Removed.
[official-gcc.git] / gcc / tree-mudflap.c
blob474c7c455469d2e70913ab94ced1cfaa5765de66
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 (! 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)
771 call = t;
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)
797 /* Got it! */
798 size = stack_alloc_op2;
799 stack_alloc_call = call;
800 /* Advance iterator to point past this allocation call. */
801 tsi_next (&initially_stmts);
802 break;
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)));
814 break;
817 else
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)),
828 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)),
841 decl))),
842 tree_cons (NULL_TREE,
843 size,
844 tree_cons (NULL_TREE,
845 build_int_2 (3, 0), /* __MF_TYPE_STACK */
846 tree_cons (NULL_TREE,
847 variable_name,
848 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 (&register_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);
867 mf_mark (decl);
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);
878 *stmt_list = NULL;
879 append_to_statement_list (t, stmt_list);
884 /* Process every variable mentioned in BIND_EXPRs. */
885 static tree
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)
892 *continue_p = 0;
893 return NULL_TREE;
896 *continue_p = 1;
898 switch (TREE_CODE (*t))
900 case BIND_EXPR:
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));
908 break;
910 default:
911 break;
914 return NULL;
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.
925 static void
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
939 label is given.
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;
953 static void
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);
976 void
977 mudflap_enqueue_decl (tree obj)
979 if (mf_marked_p (obj))
980 return;
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))
988 return;
990 if (COMPLETE_TYPE_P (TREE_TYPE (obj)))
992 tree object_size;
994 mf_mark (obj);
996 object_size = size_in_bytes (TREE_TYPE (obj));
998 if (dump_file)
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));
1014 else
1016 size_t i;
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)));
1027 return;
1030 VARRAY_PUSH_TREE (deferred_static_decls, obj);
1034 void
1035 mudflap_enqueue_constant (tree obj)
1037 tree object_size, varname;
1039 if (mf_marked_p (obj))
1040 return;
1042 if (TREE_CODE (obj) == STRING_CST)
1043 object_size = build_int_2 (TREE_STRING_LENGTH (obj), 0);
1044 else
1045 object_size = size_in_bytes (TREE_TYPE (obj));
1047 if (dump_file)
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");
1058 else
1059 varname = mf_build_string ("constant");
1061 mudflap_register_call (obj, object_size, varname);
1066 /* Emit any file-wide instrumentation. */
1067 void
1068 mudflap_finish_file (void)
1070 /* Try to give the deferred objects one final try. */
1071 if (deferred_static_decls)
1073 size_t i;
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"