OSDN Git Service

* tree-gimple.c: Rename from tree-simple.c.
[pf3gnuchains/gcc-fork.git] / gcc / tree-mudflap.c
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>
5
6 This file is part of GCC.
7
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.
12
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.
17
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.  */
22
23
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"
43
44 /* Internal function decls */
45
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 *);
53
54 static void mx_register_decls (tree, tree *);
55
56
57 /* extern mudflap functions */
58
59 static GTY ((param_is (union tree_node))) htab_t marked_trees = NULL;
60
61
62 /* Mark and return the given tree node to prevent further mudflap
63    transforms.  */
64 tree
65 mf_mark (tree t)
66 {
67   void **slot;
68
69   if (marked_trees == NULL)
70     marked_trees = htab_create_ggc (31, htab_hash_pointer, htab_eq_pointer, NULL);
71
72   slot = htab_find_slot (marked_trees, t, INSERT);
73   *slot = t;
74   return t;
75 }
76
77
78 int
79 mf_marked_p (tree t)
80 {
81   void *entry;
82
83   if (marked_trees == NULL)
84     return 0;
85
86   entry = htab_find (marked_trees, t);
87   return (entry != NULL);
88 }
89
90 static tree
91 mf_build_string (const char *string)
92 {
93   size_t len = strlen (string);
94   tree result = mf_mark (build_string (len + 1, string));
95
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;
103
104   result = build1 (ADDR_EXPR, build_pointer_type (char_type_node), result);
105
106   return mf_mark (result);
107 }
108
109 /* Perform the declaration-related mudflap tree transforms on the
110    given function.  Update its DECL_SAVED_TREE.  */
111
112 static void
113 mudflap_function_decls (void)
114 {
115   if (mf_marked_p (current_function_decl))
116     return;
117
118   push_gimplify_context ();
119
120   mf_init_extern_trees ();
121   mf_xform_decls (DECL_SAVED_TREE (current_function_decl),
122                   DECL_ARGUMENTS (current_function_decl));
123
124   pop_gimplify_context (NULL);
125 }
126
127 static bool
128 gate_mudflap (void)
129 {
130   return flag_mudflap != 0;
131 }
132
133 struct tree_opt_pass pass_mudflap_1 = 
134 {
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 */
147 };
148
149
150 /* Same as above, for the indirection-related transforms.  */
151
152 static void
153 mudflap_function_ops (void)
154 {
155   if (mf_marked_p (current_function_decl))
156     return;
157
158   push_gimplify_context ();
159
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));
163
164   mf_xform_derefs (DECL_SAVED_TREE (current_function_decl));
165
166   if (! flag_mudflap_threads)
167     mf_decl_clear_locals ();
168
169   pop_gimplify_context (NULL);
170 }
171
172 struct tree_opt_pass pass_mudflap_2 = 
173 {
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 */
186 };
187
188 /* global tree nodes */
189
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.  */
193
194 /* uintptr_t (usually "unsigned long") */
195 static GTY (()) tree mf_uintptr_type;
196
197 /* struct __mf_cache { uintptr_t low; uintptr_t high; }; */
198 static GTY (()) tree mf_cache_struct_type;
199
200 /* struct __mf_cache * const */
201 static GTY (()) tree mf_cache_structptr_type;
202
203 /* extern struct __mf_cache __mf_lookup_cache []; */
204 static GTY (()) tree mf_cache_array_decl;
205
206 /* extern const unsigned char __mf_lc_shift; */
207 static GTY (()) tree mf_cache_shift_decl;
208
209 /* extern const uintptr_t __mf_lc_mask; */
210 static GTY (()) tree mf_cache_mask_decl;
211
212 /* Their function-scope local shadows, used in single-threaded mode only. */
213
214 /* auto const unsigned char __mf_lc_shift_l; */
215 static GTY (()) tree mf_cache_shift_decl_l;
216
217 /* auto const uintptr_t __mf_lc_mask_l; */
218 static GTY (()) tree mf_cache_mask_decl_l;
219
220 /* extern void __mf_check (void *ptr, size_t sz, int type, const char *); */
221 static GTY (()) tree mf_check_fndecl;
222
223 /* extern void __mf_register (void *ptr, size_t sz, int type, const char *); */
224 static GTY (()) tree mf_register_fndecl;
225
226 /* extern void __mf_unregister (void *ptr, size_t sz); */
227 static GTY (()) tree mf_unregister_fndecl;
228
229
230 /* Initialize the global tree nodes that correspond to mf-runtime.h
231    declarations.  */
232 static void
233 mf_init_extern_trees (void)
234 {
235   static bool done = false;
236
237   if (done)
238     return;
239   done = true;
240
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");
250 }
251
252
253
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. */
257
258 static void
259 mf_decl_cache_locals (tree* body)
260 {
261   tree_stmt_iterator i = tsi_start (*body);
262   tree t;
263
264   mf_cache_shift_decl_l
265     = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_shift_decl),
266                                "__mf_lookup_shift_l"));
267
268   mf_cache_mask_decl_l
269     = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_mask_decl),
270                                "__mf_lookup_mask_l"));
271
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);
278
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);
284 }
285
286
287 static void
288 mf_decl_clear_locals (void)
289 {
290   /* Unset local shadows. */
291   mf_cache_shift_decl_l = NULL_TREE;
292   mf_cache_mask_decl_l = NULL_TREE;
293 }
294
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.  */
299
300 static tree
301 mf_varname_tree (tree decl)
302 {
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;
308
309   if (decl == NULL_TREE)
310     abort ();
311
312   if (!initialized)
313     {
314       pp_construct (buf, /* prefix */ NULL, /* line-width */ 0);
315       initialized = 1;
316     }
317   pp_clear_output_area (buf);
318
319   /* Add FILENAME[:LINENUMBER]. */
320   {
321     const char *sourcefile;
322     unsigned sourceline;
323
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>";
329
330     pp_string (buf, sourcefile);
331
332     sourceline = DECL_SOURCE_LINE (decl);
333     if (sourceline != 0)
334       {
335         pp_string (buf, ":");
336         pp_decimal_int (buf, sourceline);
337       }
338   }
339
340   if (current_function_decl != NULL_TREE)
341     {
342       /* Add (FUNCTION): */
343       pp_string (buf, " (");
344       {
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";
350
351         pp_string (buf, funcname);
352       }
353       pp_string (buf, ") ");
354     }
355   else
356     pp_string (buf, " ");
357
358   /* Add <variable-declaration>, possibly demangled.  */
359   {
360     const char *declname = NULL;
361
362     if (strcmp ("GNU C++", lang_hooks.name) == 0 &&
363         DECL_NAME (decl) != NULL)
364       {
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);
369       }
370
371     if (declname == NULL)
372       declname = (*lang_hooks.decl_printable_name) (decl, 3);
373
374     if (declname == NULL)
375       declname = "<unnamed variable>";
376
377     pp_string (buf, declname);
378   }
379
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);
384
385   return result;
386 }
387
388
389 /* And another friend, for producing a simpler message.  */
390
391 static tree
392 mf_file_function_line_tree (location_t *locus)
393 {
394   const char *file = NULL, *colon, *line, *op, *name, *cp;
395   char linebuf[18];
396   char *string;
397   tree result;
398
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>";
406
407   /* Add :LINENUMBER.  */
408   if (locus != NULL && locus->line > 0)
409     {
410       sprintf (linebuf, "%d", locus->line);
411       colon = ":";
412       line = linebuf;
413     }
414   else
415     colon = line = "";
416
417   /* Add (FUNCTION).  */
418   name = (*lang_hooks.decl_printable_name) (current_function_decl, 1);
419   if (name)
420     {
421       op = " (";
422       cp = ")";
423     }
424   else
425     op = name = cp = "";
426
427   string = concat (file, colon, line, op, name, cp, NULL);
428   result = mf_build_string (string);
429   free (string);
430
431   return result;
432 }
433
434
435 static void
436 mf_build_check_statement_for (tree addr, tree size, tree_stmt_iterator *iter,
437                               location_t *locus, tree dirflag)
438 {
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;
444
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");
449
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);
456
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);
464
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);
480
481   /* Quick validity check.
482      if (__builtin_expect ((__mf_elem->low > __mf_base)
483                            | (__mf_elem_high < __mf_base + sizeof(T) - 1),
484                            0))
485         {
486           __mf_check ();
487           ... and only if single-threaded:
488           __mf_lookup_shift_1 = f...;
489           __mf_lookup_mask_l = ...;
490         }
491      */
492
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));
497
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)));
502
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));
507
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));
511
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);
516
517   /* Build up the body of the cache-miss handling:
518      __mf_check(); refresh *_l vars.  */
519
520   stmt = NULL;
521   
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);
528
529   if (! flag_mudflap_threads)
530     {
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);
534
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);
538     }
539
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);
546 }
547
548 static void
549 mf_xform_derefs_1 (tree_stmt_iterator *iter, tree *tp,
550                    location_t *locus, tree dirflag)
551 {
552   tree type, ptr_type, addr, size, t;
553
554   /* Don't instrument read operations.  */
555   if (dirflag == integer_zero_node && flag_mudflap_ignore_reads)
556     return;
557
558   t = *tp;
559   type = TREE_TYPE (t);
560   size = TYPE_SIZE_UNIT (type);
561
562   switch (TREE_CODE (t))
563     {
564     case ARRAY_REF:
565       {
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;
570
571         op0 = TREE_OPERAND (t, 0);
572         op1 = TREE_OPERAND (t, 1);
573         while (TREE_CODE (op1) == INTEGER_CST)
574           {
575             tree dom = TYPE_DOMAIN (TREE_TYPE (op0));
576
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;
587
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;
592
593             /* Only continue if we're still looking at an array.  */
594             if (TREE_CODE (op0) != ARRAY_REF)
595               break;
596
597             op1 = TREE_OPERAND (op0, 1);
598             op0 = TREE_OPERAND (op0, 0);
599           }
600       
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);
604       }
605       break;
606
607     case INDIRECT_REF:
608       addr = TREE_OPERAND (t, 0);
609       ptr_type = TREE_TYPE (addr);
610       break;
611
612     case ARRAY_RANGE_REF:
613       warning ("mudflap checking not yet implemented for ARRAY_RANGE_REF");
614       return;
615
616     case COMPONENT_REF:
617       {
618         tree field;
619
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;
624
625         field = TREE_OPERAND (t, 1);
626
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))
631           {
632             size = bitsize_int (BITS_PER_UNIT);
633             size = size_binop (CEIL_DIV_EXPR, DECL_SIZE (field), size);
634             size = convert (sizetype, size);
635
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)));
640           }
641         else
642           {
643             ptr_type = build_pointer_type (type);
644             addr = build1 (ADDR_EXPR, ptr_type, t);
645           }
646       }
647       break;
648
649     case BIT_FIELD_REF:
650       {
651         tree ofs, rem, bpu;
652
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;
657
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);
662
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);
667
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));
671       }
672       break;
673
674     default:
675       return;
676     }
677
678   mf_build_check_statement_for (addr, size, iter, locus, dirflag);
679 }
680
681 static void
682 mf_xform_derefs (tree fnbody)
683 {
684   tree_stmt_iterator i = tsi_start (fnbody);
685
686   for (i = tsi_start (fnbody); !tsi_end_p (i); tsi_next (&i))
687     {
688       tree s = tsi_stmt (i);
689
690       /* Only a few GIMPLE statements can reference memory.  */
691       switch (TREE_CODE (s))
692         {
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;
699
700         case RETURN_EXPR:
701           if (TREE_OPERAND (s, 0) != NULL_TREE)
702             {
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);
709             }
710           break;
711
712         default:
713           ;
714         }
715     }
716 }
717
718 /* ------------------------------------------------------------------------ */
719 /* ADDR_EXPR transform */
720
721
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
726 {
727   tree param_decls;
728 };
729
730
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)
736 {
737   tree finally_stmts = NULL_TREE;
738   tree_stmt_iterator initially_stmts = tsi_start (*stmt_list);
739
740   while (decl != NULL_TREE)
741     {
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 */
749         {
750           tree size = NULL_TREE, variable_name;
751           tree unregister_fncall, unregister_fncall_params;
752           tree register_fncall, register_fncall_params;
753
754           if (DECL_DEFER_OUTPUT (decl))
755             {
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;
764
765               while(! tsi_end_p (initially_stmts))
766                 {
767                   tree t = tsi_stmt (initially_stmts);
768
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)
776                     {
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));
782                     }
783
784                   if (call != NULL_TREE)
785                     {
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])
789                         {
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));
793                           
794                           if (TREE_CODE (stack_alloc_op1) == ADDR_EXPR &&
795                               TREE_OPERAND (stack_alloc_op1, 0) == decl)
796                             {
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;
803                             }
804                         }
805                     }
806
807                   tsi_next (&initially_stmts);
808                 }
809
810               if (stack_alloc_call == NULL_TREE)
811                 {
812                   warning ("mudflap cannot handle variable-sized declaration `%s'",
813                          IDENTIFIER_POINTER (DECL_NAME (decl)));
814                   break;
815                 }
816             }
817           else
818             {
819               size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl)));
820             }
821
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);
833
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))));
849
850           /* __mf_register (...) */
851           register_fncall = build_function_call_expr (mf_register_fndecl,
852                                                       register_fncall_params);
853
854           /* Accumulate the two calls.  */
855           /* ??? Set EXPR_LOCUS.  */
856           gimplify_stmt (&register_fncall);
857           gimplify_stmt (&unregister_fncall);
858
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);
863
864           /* Accumulate the FINALLY piece. */
865           append_to_statement_list (unregister_fncall, &finally_stmts);
866
867           mf_mark (decl);
868         }
869
870       decl = TREE_CHAIN (decl);
871     }
872
873   /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */
874   if (finally_stmts != NULL_TREE)
875     {
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);
880     }
881 }
882
883
884 /* Process every variable mentioned in BIND_EXPRs.  */
885 static tree
886 mx_xfn_xform_decls (tree *t, int *continue_p, void *data)
887 {
888   struct mf_xform_decls_data* d = (struct mf_xform_decls_data*) data;
889
890   if (*t == NULL_TREE || *t == error_mark_node)
891     {
892       *continue_p = 0;
893       return NULL_TREE;
894     }
895
896   *continue_p = 1;
897
898   switch (TREE_CODE (*t))
899     {
900     case BIND_EXPR:
901       {
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;
905
906         mx_register_decls (BIND_EXPR_VARS (*t), &BIND_EXPR_BODY (*t));
907       }
908       break;
909
910     default:
911       break;
912     }
913
914   return NULL;
915 }
916
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.
919
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.
923 */
924
925 static void
926 mf_xform_decls (tree fnbody, tree fnparams)
927 {
928   struct mf_xform_decls_data d;
929   d.param_decls = fnparams;
930   walk_tree_without_duplicates (&fnbody, mx_xfn_xform_decls, &d);
931 }
932
933
934 /* ------------------------------------------------------------------------ */
935
936
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.
940 */
941
942
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.  */
947
948 static GTY (()) varray_type deferred_static_decls;
949
950 /* A list of statements for calling __mf_register() at startup time.  */
951 static GTY (()) tree enqueued_call_stmt_chain;
952
953 static void
954 mudflap_register_call (tree obj, tree object_size, tree varname)
955 {
956   tree arg, args, call_stmt;
957
958   args = tree_cons (NULL_TREE, varname, NULL_TREE);
959
960   arg = build_int_2 (4, 0); /* __MF_TYPE_STATIC */
961   args = tree_cons (NULL_TREE, arg, args);
962
963   arg = convert (size_type_node, object_size);
964   args = tree_cons (NULL_TREE, arg, args);
965
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);
969
970   mf_init_extern_trees ();
971   call_stmt = build_function_call_expr (mf_register_fndecl, args);
972
973   append_to_statement_list (call_stmt, &enqueued_call_stmt_chain);
974 }
975
976 void
977 mudflap_enqueue_decl (tree obj)
978 {
979   if (mf_marked_p (obj))
980     return;
981
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;
989
990   if (COMPLETE_TYPE_P (TREE_TYPE (obj)))
991     {
992       tree object_size;
993
994       mf_mark (obj);
995
996       object_size = size_in_bytes (TREE_TYPE (obj));
997
998       if (dump_file)
999         {
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");
1005         }
1006
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.  */
1011
1012       mudflap_register_call (obj, object_size, mf_varname_tree (obj));
1013     }
1014   else
1015     {
1016       size_t i;
1017
1018       if (! deferred_static_decls)
1019         VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list");
1020
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)
1024           {
1025             warning ("mudflap cannot track lifetime of `%s'",
1026                      IDENTIFIER_POINTER (DECL_NAME (obj)));
1027             return;
1028           }
1029
1030       VARRAY_PUSH_TREE (deferred_static_decls, obj);
1031     }
1032 }
1033
1034 void
1035 mudflap_enqueue_constant (tree obj)
1036 {
1037   tree object_size, varname;
1038
1039   if (mf_marked_p (obj))
1040     return;
1041
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));
1046
1047   if (dump_file)
1048     {
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");
1054     }
1055
1056   if (TREE_CODE (obj) == STRING_CST)
1057     varname = mf_build_string ("string literal");
1058   else
1059     varname = mf_build_string ("constant");
1060
1061   mudflap_register_call (obj, object_size, varname);
1062 }
1063
1064
1065
1066 /* Emit any file-wide instrumentation.  */
1067 void
1068 mudflap_finish_file (void)
1069 {
1070   /* Try to give the deferred objects one final try.  */
1071   if (deferred_static_decls)
1072     {
1073       size_t i;
1074
1075       for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1076         {
1077           tree obj = VARRAY_TREE (deferred_static_decls, i);
1078
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);
1083         }
1084
1085       VARRAY_CLEAR (deferred_static_decls);
1086     }
1087
1088   mflang_flush_calls (enqueued_call_stmt_chain);
1089 }
1090
1091
1092
1093 #include "gt-tree-mudflap.h"