OSDN Git Service

2004-05-17 Frank Ch. Eigler <fche@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           (! TREE_STATIC (decl)) && /* auto variable */
745           (! DECL_EXTERNAL (decl)) && /* not extern variable */
746           (TREE_TYPE (decl) != error_mark_node) && /* not decl with error */
747           (COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl))) && /* complete type */
748           (! mf_marked_p (decl)) && /* not already processed */
749           (TREE_ADDRESSABLE (decl))) /* has address taken */
750         {
751           tree size = NULL_TREE, variable_name;
752           tree unregister_fncall, unregister_fncall_params;
753           tree register_fncall, register_fncall_params;
754
755           if (DECL_DEFER_OUTPUT (decl))
756             {
757               /* Oh no ... it's probably a variable-length array (VLA).
758                  The size and address cannot be computed by merely
759                  looking at the DECL.  See gimplfiy_decl_stmt for the
760                  method by which VLA declarations turn into calls to
761                  BUILT_IN_STACK_ALLOC.  We assume that multiple
762                  VLAs declared later in the same block get allocation 
763                  code later than the others. */
764               tree stack_alloc_call = NULL_TREE;
765
766               while(! tsi_end_p (initially_stmts))
767                 {
768                   tree t = tsi_stmt (initially_stmts);
769
770                   tree call = NULL_TREE;
771                   if (TREE_CODE (t) == CALL_EXPR)
772                     call = t;
773                   else if (TREE_CODE (t) == MODIFY_EXPR &&
774                            TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR)
775                     call = TREE_OPERAND (t, 1);
776                   else if (TREE_CODE (t) == TRY_FINALLY_EXPR)
777                     {
778                       /* We hope that this is the try/finally block sometimes
779                          constructed by gimplify_bind_expr() for a BIND_EXPR
780                          that contains VLAs.  This very naive recursion
781                          appears to be sufficient.  */
782                       initially_stmts = tsi_start (TREE_OPERAND (t, 0));
783                     }
784
785                   if (call != NULL_TREE)
786                     {
787                       if (TREE_CODE (TREE_OPERAND(call, 0)) == ADDR_EXPR &&
788                           TREE_OPERAND (TREE_OPERAND (call, 0), 0) ==
789                                 implicit_built_in_decls [BUILT_IN_STACK_ALLOC])
790                         {
791                           tree stack_alloc_args = TREE_OPERAND (call, 1);
792                           tree stack_alloc_op1 = TREE_VALUE (stack_alloc_args);
793                           tree stack_alloc_op2 = TREE_VALUE (TREE_CHAIN (stack_alloc_args));
794                           
795                           if (TREE_CODE (stack_alloc_op1) == ADDR_EXPR &&
796                               TREE_OPERAND (stack_alloc_op1, 0) == decl)
797                             {
798                               /* Got it! */
799                               size = stack_alloc_op2;
800                               stack_alloc_call = call;
801                               /* Advance iterator to point past this allocation call. */
802                               tsi_next (&initially_stmts);
803                               break;
804                             }
805                         }
806                     }
807
808                   tsi_next (&initially_stmts);
809                 }
810
811               if (stack_alloc_call == NULL_TREE)
812                 {
813                   warning ("mudflap cannot handle variable-sized declaration `%s'",
814                          IDENTIFIER_POINTER (DECL_NAME (decl)));
815                   break;
816                 }
817             }
818           else
819             {
820               size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl)));
821             }
822
823           /* (& VARIABLE, sizeof (VARIABLE)) */
824           unregister_fncall_params =
825             tree_cons (NULL_TREE,
826                        convert (ptr_type_node,
827                                 mf_mark (build1 (ADDR_EXPR,
828                                                  build_pointer_type (TREE_TYPE (decl)),
829                                                  decl))),
830                        tree_cons (NULL_TREE, size, NULL_TREE));
831           /* __mf_unregister (...) */
832           unregister_fncall = build_function_call_expr (mf_unregister_fndecl,
833                                                         unregister_fncall_params);
834
835           /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */
836           variable_name = mf_varname_tree (decl);
837           register_fncall_params =
838             tree_cons (NULL_TREE,
839                    convert (ptr_type_node,
840                             mf_mark (build1 (ADDR_EXPR,
841                                              build_pointer_type (TREE_TYPE (decl)),
842                                              decl))),
843                        tree_cons (NULL_TREE,
844                                   size,
845                                   tree_cons (NULL_TREE,
846                                              build_int_2 (3, 0), /* __MF_TYPE_STACK */
847                                              tree_cons (NULL_TREE,
848                                                         variable_name,
849                                                         NULL_TREE))));
850
851           /* __mf_register (...) */
852           register_fncall = build_function_call_expr (mf_register_fndecl,
853                                                       register_fncall_params);
854
855           /* Accumulate the two calls.  */
856           /* ??? Set EXPR_LOCUS.  */
857           gimplify_stmt (&register_fncall);
858           gimplify_stmt (&unregister_fncall);
859
860           /* Add the __mf_register call at the current appending point.  */
861           if (tsi_end_p (initially_stmts))
862             internal_error ("mudflap ran off end of BIND_EXPR body");
863           tsi_link_before (& initially_stmts, register_fncall, TSI_SAME_STMT);
864
865           /* Accumulate the FINALLY piece. */
866           append_to_statement_list (unregister_fncall, &finally_stmts);
867
868           mf_mark (decl);
869         }
870
871       decl = TREE_CHAIN (decl);
872     }
873
874   /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */
875   if (finally_stmts != NULL_TREE)
876     {
877       tree t = build (TRY_FINALLY_EXPR, void_type_node,
878                       *stmt_list, finally_stmts);
879       *stmt_list = NULL;
880       append_to_statement_list (t, stmt_list);
881     }
882 }
883
884
885 /* Process every variable mentioned in BIND_EXPRs.  */
886 static tree
887 mx_xfn_xform_decls (tree *t, int *continue_p, void *data)
888 {
889   struct mf_xform_decls_data* d = (struct mf_xform_decls_data*) data;
890
891   if (*t == NULL_TREE || *t == error_mark_node)
892     {
893       *continue_p = 0;
894       return NULL_TREE;
895     }
896
897   *continue_p = 1;
898
899   switch (TREE_CODE (*t))
900     {
901     case BIND_EXPR:
902       {
903         /* Process function parameters now (but only once).  */
904         mx_register_decls (d->param_decls, &BIND_EXPR_BODY (*t));
905         d->param_decls = NULL_TREE;
906
907         mx_register_decls (BIND_EXPR_VARS (*t), &BIND_EXPR_BODY (*t));
908       }
909       break;
910
911     default:
912       break;
913     }
914
915   return NULL;
916 }
917
918 /* Perform the object lifetime tracking mudflap transform on the given function
919    tree.  The tree is mutated in place, with possibly copied subtree nodes.
920
921    For every auto variable declared, if its address is ever taken
922    within the function, then supply its lifetime to the mudflap
923    runtime with the __mf_register and __mf_unregister calls.
924 */
925
926 static void
927 mf_xform_decls (tree fnbody, tree fnparams)
928 {
929   struct mf_xform_decls_data d;
930   d.param_decls = fnparams;
931   walk_tree_without_duplicates (&fnbody, mx_xfn_xform_decls, &d);
932 }
933
934
935 /* ------------------------------------------------------------------------ */
936
937
938 /* Remember given node as a static of some kind: global data,
939    function-scope static, or an anonymous constant.  Its assembler
940    label is given.
941 */
942
943
944 /* A list of globals whose incomplete declarations we encountered.
945    Instead of emitting the __mf_register call for them here, it's
946    delayed until program finish time.  If they're still incomplete by
947    then, warnings are emitted.  */
948
949 static GTY (()) varray_type deferred_static_decls;
950
951 /* A list of statements for calling __mf_register() at startup time.  */
952 static GTY (()) tree enqueued_call_stmt_chain;
953
954 static void
955 mudflap_register_call (tree obj, tree object_size, tree varname)
956 {
957   tree arg, args, call_stmt;
958
959   args = tree_cons (NULL_TREE, varname, NULL_TREE);
960
961   arg = build_int_2 (4, 0); /* __MF_TYPE_STATIC */
962   args = tree_cons (NULL_TREE, arg, args);
963
964   arg = convert (size_type_node, object_size);
965   args = tree_cons (NULL_TREE, arg, args);
966
967   arg = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (obj)), obj);
968   arg = convert (ptr_type_node, arg);
969   args = tree_cons (NULL_TREE, arg, args);
970
971   mf_init_extern_trees ();
972   call_stmt = build_function_call_expr (mf_register_fndecl, args);
973
974   append_to_statement_list (call_stmt, &enqueued_call_stmt_chain);
975 }
976
977 void
978 mudflap_enqueue_decl (tree obj)
979 {
980   if (mf_marked_p (obj))
981     return;
982
983   /* We don't need to process variable decls that are internally
984      generated extern.  If we did, we'd end up with warnings for them
985      during mudflap_finish_file ().  That would confuse the user,
986      since the text would refer to variables that don't show up in the
987      user's source code.  */
988   if (DECL_P (obj) && DECL_EXTERNAL (obj) && DECL_ARTIFICIAL (obj))
989     return;
990
991   if (COMPLETE_TYPE_P (TREE_TYPE (obj)))
992     {
993       tree object_size;
994
995       mf_mark (obj);
996
997       object_size = size_in_bytes (TREE_TYPE (obj));
998
999       if (dump_file)
1000         {
1001           fprintf (dump_file, "enqueue_decl obj=`");
1002           print_generic_expr (dump_file, obj, dump_flags);
1003           fprintf (dump_file, "' size=");
1004           print_generic_expr (dump_file, object_size, dump_flags);
1005           fprintf (dump_file, "\n");
1006         }
1007
1008       /* NB: the above condition doesn't require TREE_USED or
1009          TREE_ADDRESSABLE.  That's because this object may be a global
1010          only used from other compilation units.  XXX: Maybe static
1011          objects could require those attributes being set.  */
1012
1013       mudflap_register_call (obj, object_size, mf_varname_tree (obj));
1014     }
1015   else
1016     {
1017       size_t i;
1018
1019       if (! deferred_static_decls)
1020         VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list");
1021
1022       /* Ugh, linear search... */
1023       for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1024         if (VARRAY_TREE (deferred_static_decls, i) == obj)
1025           {
1026             warning ("mudflap cannot track lifetime of `%s'",
1027                      IDENTIFIER_POINTER (DECL_NAME (obj)));
1028             return;
1029           }
1030
1031       VARRAY_PUSH_TREE (deferred_static_decls, obj);
1032     }
1033 }
1034
1035 void
1036 mudflap_enqueue_constant (tree obj)
1037 {
1038   tree object_size, varname;
1039
1040   if (mf_marked_p (obj))
1041     return;
1042
1043   if (TREE_CODE (obj) == STRING_CST)
1044     object_size = build_int_2 (TREE_STRING_LENGTH (obj), 0);
1045   else
1046     object_size = size_in_bytes (TREE_TYPE (obj));
1047
1048   if (dump_file)
1049     {
1050       fprintf (dump_file, "enqueue_constant obj=`");
1051       print_generic_expr (dump_file, obj, dump_flags);
1052       fprintf (dump_file, "' size=");
1053       print_generic_expr (dump_file, object_size, dump_flags);
1054       fprintf (dump_file, "\n");
1055     }
1056
1057   if (TREE_CODE (obj) == STRING_CST)
1058     varname = mf_build_string ("string literal");
1059   else
1060     varname = mf_build_string ("constant");
1061
1062   mudflap_register_call (obj, object_size, varname);
1063 }
1064
1065
1066
1067 /* Emit any file-wide instrumentation.  */
1068 void
1069 mudflap_finish_file (void)
1070 {
1071   /* Try to give the deferred objects one final try.  */
1072   if (deferred_static_decls)
1073     {
1074       size_t i;
1075
1076       for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1077         {
1078           tree obj = VARRAY_TREE (deferred_static_decls, i);
1079
1080           /* Call enqueue_decl again on the same object it has previously
1081              put into the table.  (It won't modify the table this time, so
1082              infinite iteration is not a problem.)  */
1083           mudflap_enqueue_decl (obj);
1084         }
1085
1086       VARRAY_CLEAR (deferred_static_decls);
1087     }
1088
1089   mflang_flush_calls (enqueued_call_stmt_chain);
1090 }
1091
1092
1093
1094 #include "gt-tree-mudflap.h"