OSDN Git Service

2004-06-09 Benjamin Kosnik <bkoz@redhat.com>
[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           /* 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))
753         {
754           tree size = NULL_TREE, variable_name;
755           tree unregister_fncall, unregister_fncall_params;
756           tree register_fncall, register_fncall_params;
757
758           if (DECL_DEFER_OUTPUT (decl))
759             {
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;
768
769               while(! tsi_end_p (initially_stmts))
770                 {
771                   tree t = tsi_stmt (initially_stmts);
772
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)
780                     {
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));
786                     }
787
788                   if (call != NULL_TREE)
789                     {
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])
793                         {
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));
797                           
798                           if (TREE_CODE (stack_alloc_op1) == ADDR_EXPR &&
799                               TREE_OPERAND (stack_alloc_op1, 0) == decl)
800                             {
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;
807                             }
808                         }
809                     }
810
811                   tsi_next (&initially_stmts);
812                 }
813
814               if (stack_alloc_call == NULL_TREE)
815                 {
816                   warning ("mudflap cannot handle variable-sized declaration `%s'",
817                          IDENTIFIER_POINTER (DECL_NAME (decl)));
818                   break;
819                 }
820             }
821           else
822             {
823               size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl)));
824             }
825
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);
837
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))));
853
854           /* __mf_register (...) */
855           register_fncall = build_function_call_expr (mf_register_fndecl,
856                                                       register_fncall_params);
857
858           /* Accumulate the two calls.  */
859           /* ??? Set EXPR_LOCUS.  */
860           gimplify_stmt (&register_fncall);
861           gimplify_stmt (&unregister_fncall);
862
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);
867
868           /* Accumulate the FINALLY piece.  */
869           append_to_statement_list (unregister_fncall, &finally_stmts);
870
871           mf_mark (decl);
872         }
873
874       decl = TREE_CHAIN (decl);
875     }
876
877   /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */
878   if (finally_stmts != NULL_TREE)
879     {
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);
884     }
885 }
886
887
888 /* Process every variable mentioned in BIND_EXPRs.  */
889 static tree
890 mx_xfn_xform_decls (tree *t, int *continue_p, void *data)
891 {
892   struct mf_xform_decls_data* d = (struct mf_xform_decls_data*) data;
893
894   if (*t == NULL_TREE || *t == error_mark_node)
895     {
896       *continue_p = 0;
897       return NULL_TREE;
898     }
899
900   *continue_p = 1;
901
902   switch (TREE_CODE (*t))
903     {
904     case BIND_EXPR:
905       {
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;
909
910         mx_register_decls (BIND_EXPR_VARS (*t), &BIND_EXPR_BODY (*t));
911       }
912       break;
913
914     default:
915       break;
916     }
917
918   return NULL;
919 }
920
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.
923
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.
927 */
928
929 static void
930 mf_xform_decls (tree fnbody, tree fnparams)
931 {
932   struct mf_xform_decls_data d;
933   d.param_decls = fnparams;
934   walk_tree_without_duplicates (&fnbody, mx_xfn_xform_decls, &d);
935 }
936
937
938 /* ------------------------------------------------------------------------ */
939
940
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.
944 */
945
946
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.  */
951
952 static GTY (()) varray_type deferred_static_decls;
953
954 /* A list of statements for calling __mf_register() at startup time.  */
955 static GTY (()) tree enqueued_call_stmt_chain;
956
957 static void
958 mudflap_register_call (tree obj, tree object_size, tree varname)
959 {
960   tree arg, args, call_stmt;
961
962   args = tree_cons (NULL_TREE, varname, NULL_TREE);
963
964   arg = build_int_2 (4, 0); /* __MF_TYPE_STATIC */
965   args = tree_cons (NULL_TREE, arg, args);
966
967   arg = convert (size_type_node, object_size);
968   args = tree_cons (NULL_TREE, arg, args);
969
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);
973
974   mf_init_extern_trees ();
975   call_stmt = build_function_call_expr (mf_register_fndecl, args);
976
977   append_to_statement_list (call_stmt, &enqueued_call_stmt_chain);
978 }
979
980 void
981 mudflap_enqueue_decl (tree obj)
982 {
983   if (mf_marked_p (obj))
984     return;
985
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;
993
994   if (COMPLETE_TYPE_P (TREE_TYPE (obj)))
995     {
996       tree object_size;
997
998       mf_mark (obj);
999
1000       object_size = size_in_bytes (TREE_TYPE (obj));
1001
1002       if (dump_file)
1003         {
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");
1009         }
1010
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.  */
1015
1016       mudflap_register_call (obj, object_size, mf_varname_tree (obj));
1017     }
1018   else
1019     {
1020       size_t i;
1021
1022       if (! deferred_static_decls)
1023         VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list");
1024
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)
1028           {
1029             warning ("mudflap cannot track lifetime of `%s'",
1030                      IDENTIFIER_POINTER (DECL_NAME (obj)));
1031             return;
1032           }
1033
1034       VARRAY_PUSH_TREE (deferred_static_decls, obj);
1035     }
1036 }
1037
1038 void
1039 mudflap_enqueue_constant (tree obj)
1040 {
1041   tree object_size, varname;
1042
1043   if (mf_marked_p (obj))
1044     return;
1045
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));
1050
1051   if (dump_file)
1052     {
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");
1058     }
1059
1060   if (TREE_CODE (obj) == STRING_CST)
1061     varname = mf_build_string ("string literal");
1062   else
1063     varname = mf_build_string ("constant");
1064
1065   mudflap_register_call (obj, object_size, varname);
1066 }
1067
1068
1069
1070 /* Emit any file-wide instrumentation.  */
1071 void
1072 mudflap_finish_file (void)
1073 {
1074   /* Try to give the deferred objects one final try.  */
1075   if (deferred_static_decls)
1076     {
1077       size_t i;
1078
1079       for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1080         {
1081           tree obj = VARRAY_TREE (deferred_static_decls, i);
1082
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);
1087         }
1088
1089       VARRAY_CLEAR (deferred_static_decls);
1090     }
1091
1092   mflang_flush_calls (enqueued_call_stmt_chain);
1093 }
1094
1095
1096
1097 #include "gt-tree-mudflap.h"