OSDN Git Service

PR c++/15815
[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 "hard-reg-set.h"
30 #include "rtl.h"
31 #include "tree.h"
32 #include "tm_p.h"
33 #include "basic-block.h"
34 #include "flags.h"
35 #include "function.h"
36 #include "tree-inline.h"
37 #include "tree-gimple.h"
38 #include "tree-flow.h"
39 #include "tree-mudflap.h"
40 #include "tree-dump.h"
41 #include "tree-pass.h"
42 #include "hashtab.h"
43 #include "diagnostic.h"
44 #include <demangle.h>
45 #include "langhooks.h"
46 #include "ggc.h"
47 #include "cgraph.h"
48
49 /* Internal function decls */
50
51 /* Helpers.  */
52 static tree mf_build_string (const char *string);
53 static tree mf_varname_tree (tree);
54 static tree mf_file_function_line_tree (location_t);
55
56 /* Indirection-related instrumentation.  */
57 static void mf_decl_cache_locals (void);
58 static void mf_decl_clear_locals (void);
59 static void mf_xform_derefs (void);
60 static void execute_mudflap_function_ops (void);
61
62 /* Addressable variables instrumentation.  */
63 static void mf_xform_decls (tree, tree);
64 static tree mx_xfn_xform_decls (tree *, int *, void *);
65 static void mx_register_decls (tree, tree *);
66 static void execute_mudflap_function_decls (void);
67
68
69 /* ------------------------------------------------------------------------ */
70 /* Some generally helpful functions for mudflap instrumentation.  */
71
72 /* Build a reference to a literal string.  */
73 static tree
74 mf_build_string (const char *string)
75 {
76   size_t len = strlen (string);
77   tree result = mf_mark (build_string (len + 1, string));
78
79   TREE_TYPE (result)
80       = build_array_type (char_type_node,
81                           build_index_type (build_int_2 (len, 0)));
82   TREE_CONSTANT (result) = 1;
83   TREE_INVARIANT (result) = 1;
84   TREE_READONLY (result) = 1;
85   TREE_STATIC (result) = 1;
86
87   result = build1 (ADDR_EXPR, build_pointer_type (char_type_node), result);
88
89   return mf_mark (result);
90 }
91
92 /* Create a properly typed STRING_CST node that describes the given
93    declaration.  It will be used as an argument for __mf_register().
94    Try to construct a helpful string, including file/function/variable
95    name.  */
96
97 static tree
98 mf_varname_tree (tree decl)
99 {
100   static pretty_printer buf_rec;
101   static int initialized = 0;
102   pretty_printer *buf = & buf_rec;
103   const char *buf_contents;
104   tree result;
105
106   if (decl == NULL_TREE)
107     abort ();
108
109   if (!initialized)
110     {
111       pp_construct (buf, /* prefix */ NULL, /* line-width */ 0);
112       initialized = 1;
113     }
114   pp_clear_output_area (buf);
115
116   /* Add FILENAME[:LINENUMBER].  */
117   {
118     expanded_location xloc = expand_location (DECL_SOURCE_LOCATION (decl));
119     const char *sourcefile;
120     unsigned sourceline = xloc.line;
121
122     sourcefile = xloc.file;
123     if (sourcefile == NULL && current_function_decl != NULL_TREE)
124       sourcefile = DECL_SOURCE_FILE (current_function_decl);
125     if (sourcefile == NULL)
126       sourcefile = "<unknown file>";
127
128     pp_string (buf, sourcefile);
129
130     if (sourceline != 0)
131       {
132         pp_string (buf, ":");
133         pp_decimal_int (buf, sourceline);
134       }
135   }
136
137   if (current_function_decl != NULL_TREE)
138     {
139       /* Add (FUNCTION): */
140       pp_string (buf, " (");
141       {
142         const char *funcname = NULL;
143         if (DECL_NAME (current_function_decl))
144           funcname = lang_hooks.decl_printable_name (current_function_decl, 1);
145         if (funcname == NULL)
146           funcname = "anonymous fn";
147
148         pp_string (buf, funcname);
149       }
150       pp_string (buf, ") ");
151     }
152   else
153     pp_string (buf, " ");
154
155   /* Add <variable-declaration>, possibly demangled.  */
156   {
157     const char *declname = NULL;
158
159     if (strcmp ("GNU C++", lang_hooks.name) == 0 &&
160         DECL_NAME (decl) != NULL)
161       {
162         /* The gcc/cp decl_printable_name hook doesn't do as good a job as
163            the libiberty demangler.  */
164         declname = cplus_demangle (IDENTIFIER_POINTER (DECL_NAME (decl)),
165                                    DMGL_AUTO | DMGL_VERBOSE);
166       }
167
168     if (declname == NULL)
169       declname = lang_hooks.decl_printable_name (decl, 3);
170
171     if (declname == NULL)
172       declname = "<unnamed variable>";
173
174     pp_string (buf, declname);
175   }
176
177   /* Return the lot as a new STRING_CST.  */
178   buf_contents = pp_base_formatted_text (buf);
179   result = mf_build_string (buf_contents);
180   pp_clear_output_area (buf);
181
182   return result;
183 }
184
185
186 /* And another friend, for producing a simpler message.  */
187
188 static tree
189 mf_file_function_line_tree (location_t location)
190 {
191   expanded_location xloc = expand_location (location);
192   const char *file = NULL, *colon, *line, *op, *name, *cp;
193   char linebuf[18];
194   char *string;
195   tree result;
196
197   /* Add FILENAME[:LINENUMBER]. */
198   if (xloc.file == NULL && current_function_decl != NULL_TREE)
199     xloc.file = DECL_SOURCE_FILE (current_function_decl);
200   if (xloc.file == NULL)
201     xloc.file = "<unknown file>";
202
203   if (xloc.line > 0)
204     {
205       sprintf (linebuf, "%d", xloc.line);
206       colon = ":";
207       line = linebuf;
208     }
209   else
210     colon = line = "";
211
212   /* Add (FUNCTION).  */
213   name = lang_hooks.decl_printable_name (current_function_decl, 1);
214   if (name)
215     {
216       op = " (";
217       cp = ")";
218     }
219   else
220     op = name = cp = "";
221
222   string = concat (file, colon, line, op, name, cp, NULL);
223   result = mf_build_string (string);
224   free (string);
225
226   return result;
227 }
228
229
230 /* global tree nodes */
231
232 /* Global tree objects for global variables and functions exported by
233    mudflap runtime library.  mf_init_extern_trees must be called
234    before using these.  */
235
236 /* uintptr_t (usually "unsigned long") */
237 static GTY (()) tree mf_uintptr_type;
238
239 /* struct __mf_cache { uintptr_t low; uintptr_t high; }; */
240 static GTY (()) tree mf_cache_struct_type;
241
242 /* struct __mf_cache * const */
243 static GTY (()) tree mf_cache_structptr_type;
244
245 /* extern struct __mf_cache __mf_lookup_cache []; */
246 static GTY (()) tree mf_cache_array_decl;
247
248 /* extern unsigned char __mf_lc_shift; */
249 static GTY (()) tree mf_cache_shift_decl;
250
251 /* extern uintptr_t __mf_lc_mask; */
252 static GTY (()) tree mf_cache_mask_decl;
253
254 /* Their function-scope local shadows, used in single-threaded mode only. */
255
256 /* auto const unsigned char __mf_lc_shift_l; */
257 static GTY (()) tree mf_cache_shift_decl_l;
258
259 /* auto const uintptr_t __mf_lc_mask_l; */
260 static GTY (()) tree mf_cache_mask_decl_l;
261
262 /* extern void __mf_check (void *ptr, size_t sz, int type, const char *); */
263 static GTY (()) tree mf_check_fndecl;
264
265 /* extern void __mf_register (void *ptr, size_t sz, int type, const char *); */
266 static GTY (()) tree mf_register_fndecl;
267
268 /* extern void __mf_unregister (void *ptr, size_t sz, int type); */
269 static GTY (()) tree mf_unregister_fndecl;
270
271 /* Helper for mudflap_init: construct a decl with the given category,
272    name, and type, mark it an external reference, and pushdecl it.  */
273 static inline tree
274 mf_make_builtin (enum tree_code category, const char *name, tree type)
275 {
276   tree decl = mf_mark (build_decl (category, get_identifier (name), type));
277   TREE_PUBLIC (decl) = 1;
278   DECL_EXTERNAL (decl) = 1;
279   lang_hooks.decls.pushdecl (decl);
280   return decl;
281 }
282
283 /* Helper for mudflap_init: construct a tree corresponding to the type
284      struct __mf_cache { uintptr_t low; uintptr_t high; };
285      where uintptr_t is the FIELD_TYPE argument.  */
286 static inline tree
287 mf_make_mf_cache_struct_type (tree field_type)
288 {
289   /* There is, abominably, no language-independent way to construct a
290      RECORD_TYPE.  So we have to call the basic type construction
291      primitives by hand.  */
292   tree fieldlo = build_decl (FIELD_DECL, get_identifier ("low"), field_type);
293   tree fieldhi = build_decl (FIELD_DECL, get_identifier ("high"), field_type);
294
295   tree struct_type = make_node (RECORD_TYPE);
296   DECL_CONTEXT (fieldlo) = struct_type;
297   DECL_CONTEXT (fieldhi) = struct_type;
298   TREE_CHAIN (fieldlo) = fieldhi;
299   TYPE_FIELDS (struct_type) = fieldlo;
300   TYPE_NAME (struct_type) = get_identifier ("__mf_cache");
301   layout_type (struct_type);
302
303   return struct_type;
304 }
305
306 #define build_function_type_3(rtype, arg1, arg2, arg3) \
307  build_function_type (rtype, tree_cons (0, arg1, tree_cons (0, arg2, \
308                              tree_cons (0, arg3, void_list_node))))
309 #define build_function_type_4(rtype, arg1, arg2, arg3, arg4) \
310  build_function_type (rtype, tree_cons (0, arg1, tree_cons (0, arg2, \
311                              tree_cons (0, arg3, tree_cons (0, arg4, \
312                              void_list_node)))))
313
314 /* Initialize the global tree nodes that correspond to mf-runtime.h
315    declarations.  */
316 void
317 mudflap_init (void)
318 {
319   static bool done = false;
320   tree mf_const_string_type;
321   tree mf_cache_array_type;
322   tree mf_check_register_fntype;
323   tree mf_unregister_fntype;
324
325   if (done)
326     return;
327   done = true;
328
329   mf_uintptr_type = lang_hooks.types.type_for_mode (ptr_mode,
330                                                     /*unsignedp=*/true);
331   mf_const_string_type
332     = build_pointer_type (build_qualified_type
333                           (char_type_node, TYPE_QUAL_CONST));
334
335   mf_cache_struct_type = mf_make_mf_cache_struct_type (mf_uintptr_type);
336   mf_cache_structptr_type = build_pointer_type (mf_cache_struct_type);
337   mf_cache_array_type = build_array_type (mf_cache_struct_type, 0);
338   mf_check_register_fntype =
339     build_function_type_4 (void_type_node, ptr_type_node, size_type_node,
340                            integer_type_node, mf_const_string_type);
341   mf_unregister_fntype =
342     build_function_type_3 (void_type_node, ptr_type_node, size_type_node,
343                            integer_type_node);
344
345   mf_cache_array_decl = mf_make_builtin (VAR_DECL, "__mf_lookup_cache",
346                                          mf_cache_array_type);
347   mf_cache_shift_decl = mf_make_builtin (VAR_DECL, "__mf_lc_shift",
348                                          unsigned_char_type_node);
349   mf_cache_mask_decl = mf_make_builtin (VAR_DECL, "__mf_lc_mask",
350                                         mf_uintptr_type);
351   mf_check_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_check",
352                                      mf_check_register_fntype);
353   mf_register_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_register",
354                                         mf_check_register_fntype);
355   mf_unregister_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_unregister",
356                                           mf_unregister_fntype);
357 }
358 #undef build_function_type_4
359 #undef build_function_type_3
360
361
362 /* ------------------------------------------------------------------------ */
363 /* Memory reference transforms. Perform the mudflap indirection-related
364    tree transforms on the current function.
365
366    This is the second part of the mudflap instrumentation.  It works on
367    low-level GIMPLE using the CFG, because we want to run this pass after
368    tree optimizations have been performed, but we have to preserve the CFG
369    for expansion from trees to RTL.  */
370
371 static void
372 execute_mudflap_function_ops (void)
373 {
374   if (mf_marked_p (current_function_decl))
375     return;
376
377   push_gimplify_context ();
378
379   /* In multithreaded mode, don't cache the lookup cache parameters.  */
380   if (! flag_mudflap_threads)
381     mf_decl_cache_locals ();
382
383   mf_xform_derefs ();
384
385   if (! flag_mudflap_threads)
386     mf_decl_clear_locals ();
387
388   pop_gimplify_context (NULL);
389 }
390
391 /* Create and initialize local shadow variables for the lookup cache
392    globals.  Put their decls in the *_l globals for use by
393    mf_build_check_statement_for. */
394
395 static void
396 mf_decl_cache_locals (void)
397 {
398   tree t, shift_init_stmts, mask_init_stmts;
399   tree_stmt_iterator tsi;
400
401   /* Build the cache vars.  */
402   mf_cache_shift_decl_l
403     = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_shift_decl),
404                                "__mf_lookup_shift_l"));
405
406   mf_cache_mask_decl_l
407     = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_mask_decl),
408                                "__mf_lookup_mask_l"));
409
410   /* Build initialization nodes for the cache vars.  We just load the
411      globals into the cache variables.  */
412   t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_shift_decl_l),
413              mf_cache_shift_decl_l, mf_cache_shift_decl);
414   SET_EXPR_LOCATION (t, DECL_SOURCE_LOCATION (current_function_decl));
415   gimplify_to_stmt_list (&t);
416   shift_init_stmts = t;
417
418   t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_mask_decl_l),
419              mf_cache_mask_decl_l, mf_cache_mask_decl);
420   SET_EXPR_LOCATION (t, DECL_SOURCE_LOCATION (current_function_decl));
421   gimplify_to_stmt_list (&t);
422   mask_init_stmts = t;
423
424   /* Anticipating multiple entry points, we insert the cache vars
425      initializers in each successor of the ENTRY_BLOCK_PTR.  */
426   for (tsi = tsi_start (shift_init_stmts);
427        ! tsi_end_p (tsi);
428        tsi_next (&tsi))
429     insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR);
430
431   for (tsi = tsi_start (mask_init_stmts);
432        ! tsi_end_p (tsi);
433        tsi_next (&tsi))
434     insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR);
435   bsi_commit_edge_inserts (NULL);
436 }
437
438
439 static void
440 mf_decl_clear_locals (void)
441 {
442   /* Unset local shadows. */
443   mf_cache_shift_decl_l = NULL_TREE;
444   mf_cache_mask_decl_l = NULL_TREE;
445 }
446
447 static void
448 mf_build_check_statement_for (tree addr, tree size,
449                               block_stmt_iterator *instr_bsi,
450                               location_t *locus, tree dirflag)
451 {
452   tree_stmt_iterator head, tsi;
453   tree ptrtype = TREE_TYPE (addr);
454   block_stmt_iterator bsi;
455   basic_block cond_bb, then_bb, join_bb;
456   edge e;
457   tree cond, t, u, v, l1, l2;
458   tree mf_value;
459   tree mf_base;
460   tree mf_elem;
461
462   /* We first need to split the current basic block, and start altering
463      the CFG.  This allows us to insert the statements we're about to
464      construct into the right basic blocks.  The label l1 is the label
465      of the block for the THEN clause of the conditional jump we're
466      about to construct, and l2 is the ELSE clause, which is just the
467      continuation of the old statement stream.  */
468   l1 = create_artificial_label ();
469   l2 = create_artificial_label ();
470   cond_bb = bb_for_stmt (bsi_stmt (*instr_bsi));
471   bsi = *instr_bsi;
472   bsi_prev (&bsi);
473   if (! bsi_end_p (bsi))
474     {
475       e = split_block (cond_bb, bsi_stmt (bsi));
476       cond_bb = e->src;
477       join_bb = e->dest;
478     }
479   else
480     {
481       join_bb = cond_bb;
482       cond_bb = create_empty_bb (join_bb->prev_bb);
483       e = make_edge (cond_bb, join_bb, 0);
484     }
485   e->flags = EDGE_FALSE_VALUE;
486   then_bb = create_empty_bb (cond_bb);
487   make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
488   make_edge (then_bb, join_bb, EDGE_FALLTHRU);
489
490   /* We expect that the conditional jump we will construct will not
491      be taken very often as it basically is an exception condition.  */
492   predict_edge_def (then_bb->pred, PRED_MUDFLAP, NOT_TAKEN);
493
494   /* Update dominance info.  Note that bb_join's data was
495      updated by split_block.  */
496   if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
497     {
498       set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
499       set_immediate_dominator (CDI_DOMINATORS, join_bb, cond_bb);
500     }
501
502   /* Build our local variables.  */
503   mf_value = create_tmp_var (ptrtype, "__mf_value");
504   mf_elem = create_tmp_var (mf_cache_structptr_type, "__mf_elem");
505   mf_base = create_tmp_var (mf_uintptr_type, "__mf_base");
506
507   /* Build: __mf_value = <address expression>.  */
508   t = build (MODIFY_EXPR, void_type_node, mf_value, unshare_expr (addr));
509   SET_EXPR_LOCUS (t, locus);
510   gimplify_to_stmt_list (&t);
511   head = tsi_start (t);
512   tsi = tsi_last (t);
513
514   /* Build: __mf_base = (uintptr_t)__mf_value.  */
515   t = build (MODIFY_EXPR, void_type_node, mf_base,
516              build1 (NOP_EXPR, mf_uintptr_type, mf_value));
517   SET_EXPR_LOCUS (t, locus);
518   gimplify_to_stmt_list (&t);
519   tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
520
521   /* Build: __mf_elem = &__mf_lookup_cache [(__mf_base >> __mf_shift)
522                                             & __mf_mask].  */
523   t = build (RSHIFT_EXPR, mf_uintptr_type, mf_base,
524              (flag_mudflap_threads ? mf_cache_shift_decl : mf_cache_shift_decl_l));
525   t = build (BIT_AND_EXPR, mf_uintptr_type, t,
526              (flag_mudflap_threads ? mf_cache_mask_decl : mf_cache_mask_decl_l));
527   t = build (ARRAY_REF,
528              TREE_TYPE (TREE_TYPE (mf_cache_array_decl)),
529              mf_cache_array_decl, t, NULL_TREE, NULL_TREE);
530   t = build1 (ADDR_EXPR, mf_cache_structptr_type, t);
531   t = build (MODIFY_EXPR, void_type_node, mf_elem, t);
532   SET_EXPR_LOCUS (t, locus);
533   gimplify_to_stmt_list (&t);
534   tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
535
536   /* Quick validity check.
537
538      if (__mf_elem->low > __mf_base
539          || (__mf_elem_high < __mf_base + sizeof(T) - 1))
540         {
541           __mf_check ();
542           ... and only if single-threaded:
543           __mf_lookup_shift_1 = f...;
544           __mf_lookup_mask_l = ...;
545         }
546
547      It is expected that this body of code is rarely executed so we mark
548      the edge to the THEN clause of the conditional jump as unlikely.  */
549
550   /* Construct t <-- '__mf_elem->low  > __mf_base'.  */
551   t = build (COMPONENT_REF, mf_uintptr_type,
552              build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
553              TYPE_FIELDS (mf_cache_struct_type), NULL_TREE);
554   t = build (GT_EXPR, boolean_type_node, t, mf_base);
555
556   /* Construct '__mf_elem->high < __mf_base + sizeof(T) - 1'.
557
558      First build:
559         1) u <--  '__mf_elem->high'
560         2) v <--  '__mf_base + sizeof (T) - 1'.
561
562      Then build 'u <-- (u < v).  */
563
564
565   u = build (COMPONENT_REF, mf_uintptr_type,
566              build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
567              TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type)), NULL_TREE);
568
569   v = convert (mf_uintptr_type,
570                size_binop (MINUS_EXPR, size, size_one_node));
571   v = fold (build (PLUS_EXPR, mf_uintptr_type, mf_base, v));
572
573   u = build (LT_EXPR, boolean_type_node, u, v);
574
575   /* Build the composed conditional: t <-- 't || u'.  Then store the
576      result of the evaluation of 't' in a temporary variable which we
577      can use as the condition for the conditional jump.  */
578   t = build (TRUTH_OR_EXPR, boolean_type_node, t, u);
579   cond = create_tmp_var (boolean_type_node, "__mf_unlikely_cond");
580   t = build (MODIFY_EXPR, boolean_type_node, cond, t);
581   gimplify_to_stmt_list (&t);
582   tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
583
584   /* Build the conditional jump.  'cond' is just a temporary so we can
585      simply build a void COND_EXPR.  We do need labels in both arms though.  */
586   t = build (COND_EXPR, void_type_node, cond,
587              build (GOTO_EXPR, void_type_node, tree_block_label (then_bb)),
588              build (GOTO_EXPR, void_type_node, tree_block_label (join_bb)));
589   SET_EXPR_LOCUS (t, locus);
590   tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
591
592   /* At this point, after so much hard work, we have only constructed
593      the conditional jump,
594
595      if (__mf_elem->low > __mf_base
596          || (__mf_elem_high < __mf_base + sizeof(T) - 1))
597
598      The lowered GIMPLE tree representing this code is in the statement
599      list starting at 'head'.
600
601      We can insert this now in the current basic block, ie. the one that
602      the statement we're instrumenting was originally in.  */
603   bsi = bsi_last (cond_bb);
604   for (tsi = head; ! tsi_end_p (tsi); tsi_next (&tsi))
605     bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_CONTINUE_LINKING);
606
607   /*  Now build up the body of the cache-miss handling:
608
609      __mf_check();
610      refresh *_l vars.
611
612      This is the body of the conditional.  */
613   
614   u = tree_cons (NULL_TREE,
615                  mf_file_function_line_tree (locus == NULL ? UNKNOWN_LOCATION
616                                              : *locus),
617                  NULL_TREE);
618   u = tree_cons (NULL_TREE, dirflag, u);
619   u = tree_cons (NULL_TREE, size, u);
620   u = tree_cons (NULL_TREE, mf_value, u);
621   t = build_function_call_expr (mf_check_fndecl, u);
622   gimplify_to_stmt_list (&t);
623   head = tsi_start (t);
624   tsi = tsi_last (t);
625
626   if (! flag_mudflap_threads)
627     {
628       t = build (MODIFY_EXPR, void_type_node,
629                  mf_cache_shift_decl_l, mf_cache_shift_decl);
630       tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
631
632       t = build (MODIFY_EXPR, void_type_node,
633                  mf_cache_mask_decl_l, mf_cache_mask_decl);
634       tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING);
635     }
636
637   /* Insert the check code in the THEN block.  */
638   bsi = bsi_start (then_bb);
639   for (tsi = head; ! tsi_end_p (tsi); tsi_next (&tsi))
640     bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_CONTINUE_LINKING);
641
642   *instr_bsi = bsi_start (join_bb);
643   bsi_next (instr_bsi);
644 }
645
646 static void
647 mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp,
648                    location_t *locus, tree dirflag)
649 {
650   tree type, ptr_type, addr, size, t;
651
652   /* Don't instrument read operations.  */
653   if (dirflag == integer_zero_node && flag_mudflap_ignore_reads)
654     return;
655
656   t = *tp;
657   type = TREE_TYPE (t);
658   size = TYPE_SIZE_UNIT (type);
659
660   switch (TREE_CODE (t))
661     {
662     case ARRAY_REF:
663       {
664         /* Omit checking if we can statically determine that the access is
665            valid.  For non-addressable local arrays this is not optional,
666            since we won't have called __mf_register for the object.  */
667         tree op0, op1;
668
669         op0 = TREE_OPERAND (t, 0);
670         op1 = TREE_OPERAND (t, 1);
671         while (TREE_CODE (op1) == INTEGER_CST)
672           {
673             tree dom = TYPE_DOMAIN (TREE_TYPE (op0));
674
675             /* Test for index in range.  Break if not.  */
676             if (!dom
677                 || (! TYPE_MIN_VALUE (dom)
678                     || ! really_constant_p (TYPE_MIN_VALUE (dom)))
679                 || (! TYPE_MAX_VALUE (dom)
680                     || ! really_constant_p (TYPE_MAX_VALUE (dom)))
681                 || (tree_int_cst_lt (op1, TYPE_MIN_VALUE (dom))
682                     || tree_int_cst_lt (TYPE_MAX_VALUE (dom), op1)))
683               break;
684
685             /* If we're looking at a non-external VAR_DECL, then the 
686                access must be ok.  */
687             if (TREE_CODE (op0) == VAR_DECL && !DECL_EXTERNAL (op0))
688               return;
689
690             /* Only continue if we're still looking at an array.  */
691             if (TREE_CODE (op0) != ARRAY_REF)
692               break;
693
694             op1 = TREE_OPERAND (op0, 1);
695             op0 = TREE_OPERAND (op0, 0);
696           }
697       
698         /* If we got here, we couldn't statically the check.  */
699         ptr_type = build_pointer_type (type);
700         addr = build1 (ADDR_EXPR, ptr_type, t);
701       }
702       break;
703
704     case INDIRECT_REF:
705       addr = TREE_OPERAND (t, 0);
706       ptr_type = TREE_TYPE (addr);
707       break;
708
709     case ARRAY_RANGE_REF:
710       warning ("mudflap checking not yet implemented for ARRAY_RANGE_REF");
711       return;
712
713     case COMPONENT_REF:
714       {
715         tree field;
716
717         /* If we're not dereferencing something, then the access
718            must be ok.  */
719         if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
720           return;
721
722         field = TREE_OPERAND (t, 1);
723
724         /* If we're looking at a bit field, then we can't take its address
725            with ADDR_EXPR -- lang_hooks.mark_addressable will error.  Do
726            things the hard way with PLUS.  */
727         if (DECL_BIT_FIELD_TYPE (field))
728           {
729             if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST)
730               size = DECL_SIZE_UNIT (field);
731
732             addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
733             addr = fold_convert (ptr_type_node, addr);
734             addr = fold (build (PLUS_EXPR, ptr_type_node,
735                                 addr, fold_convert (ptr_type_node,
736                                                     byte_position (field))));
737           }
738         else
739           {
740             ptr_type = build_pointer_type (type);
741             addr = build1 (ADDR_EXPR, ptr_type, t);
742           }
743       }
744       break;
745
746     case BIT_FIELD_REF:
747       {
748         tree ofs, rem, bpu;
749
750         /* If we're not dereferencing something, then the access
751            must be ok.  */
752         if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
753           return;
754
755         bpu = bitsize_int (BITS_PER_UNIT);
756         ofs = convert (bitsizetype, TREE_OPERAND (t, 2));
757         rem = size_binop (TRUNC_MOD_EXPR, ofs, bpu);
758         ofs = size_binop (TRUNC_DIV_EXPR, ofs, bpu);
759
760         size = convert (bitsizetype, TREE_OPERAND (t, 1));
761         size = size_binop (PLUS_EXPR, size, rem);
762         size = size_binop (CEIL_DIV_EXPR, size, bpu);
763         size = convert (sizetype, size);
764
765         addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
766         addr = convert (ptr_type_node, addr);
767         addr = fold (build (PLUS_EXPR, ptr_type_node, addr, ofs));
768       }
769       break;
770
771     default:
772       return;
773     }
774
775   mf_build_check_statement_for (addr, size, iter, locus, dirflag);
776 }
777
778 static void
779 mf_xform_derefs (void)
780 {
781   basic_block bb, next;
782   block_stmt_iterator i;
783   int saved_last_basic_block = last_basic_block;
784
785   bb = ENTRY_BLOCK_PTR ->next_bb;
786   do
787     {
788       next = bb->next_bb;
789       for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
790         {
791           tree s = bsi_stmt (i);
792
793           /* Only a few GIMPLE statements can reference memory.  */
794           switch (TREE_CODE (s))
795             {
796             case MODIFY_EXPR:
797               mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
798                                  integer_one_node);
799               mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 1), EXPR_LOCUS (s),
800                                  integer_zero_node);
801               break;
802
803             case RETURN_EXPR:
804               if (TREE_OPERAND (s, 0) != NULL_TREE)
805                 {
806                   if (TREE_CODE (TREE_OPERAND (s, 0)) == MODIFY_EXPR)
807                     mf_xform_derefs_1 (&i, &TREE_OPERAND (TREE_OPERAND (s, 0), 1),
808                                        EXPR_LOCUS (s), integer_zero_node);
809                   else
810                     mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
811                                        integer_zero_node);
812                 }
813               break;
814
815             default:
816               ;
817             }
818         }
819       bb = next;
820     }
821   while (bb && bb->index <= saved_last_basic_block);
822 }
823
824 /* ------------------------------------------------------------------------ */
825 /* ADDR_EXPR transforms.  Perform the declaration-related mudflap tree
826    transforms on the current function.
827
828    This is the first part of the mudflap instrumentation.  It works on
829    high-level GIMPLE because after lowering, all variables are moved out
830    of their BIND_EXPR binding context, and we lose liveness information
831    for the declarations we wish to instrument.  */
832
833 static void
834 execute_mudflap_function_decls (void)
835 {
836   if (mf_marked_p (current_function_decl))
837     return;
838
839   push_gimplify_context ();
840
841   mf_xform_decls (DECL_SAVED_TREE (current_function_decl),
842                   DECL_ARGUMENTS (current_function_decl));
843
844   pop_gimplify_context (NULL);
845 }
846
847 /* This struct is passed between mf_xform_decls to store state needed
848    during the traversal searching for objects that have their
849    addresses taken.  */
850 struct mf_xform_decls_data
851 {
852   tree param_decls;
853 };
854
855
856 /* Synthesize a CALL_EXPR and a TRY_FINALLY_EXPR, for this chain of
857    _DECLs if appropriate.  Arrange to call the __mf_register function
858    now, and the __mf_unregister function later for each.  */
859 static void
860 mx_register_decls (tree decl, tree *stmt_list)
861 {
862   tree finally_stmts = NULL_TREE;
863   tree_stmt_iterator initially_stmts = tsi_start (*stmt_list);
864
865   while (decl != NULL_TREE)
866     {
867       /* Eligible decl?  */
868       if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
869           /* It must be a non-external, automatic variable.  */
870           && ! DECL_EXTERNAL (decl)
871           && ! TREE_STATIC (decl)
872           /* The decl must have its address taken.  */
873           && TREE_ADDRESSABLE (decl)
874           /* The type of the variable must be complete.  */
875           && COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl))
876           /* Don't process the same decl twice.  */
877           && ! mf_marked_p (decl))
878         {
879           tree size = NULL_TREE, variable_name;
880           tree unregister_fncall, unregister_fncall_params;
881           tree register_fncall, register_fncall_params;
882
883           if (DECL_DEFER_OUTPUT (decl))
884             {
885               /* Oh no ... it's probably a variable-length array (VLA).
886                  The size and address cannot be computed by merely
887                  looking at the DECL.  See gimplify_decl_stmt for the
888                  method by which VLA declarations turn into calls to
889                  BUILT_IN_STACK_ALLOC.  We assume that multiple
890                  VLAs declared later in the same block get allocation 
891                  code later than the others.  */
892               tree stack_alloc_call = NULL_TREE;
893
894               while(! tsi_end_p (initially_stmts))
895                 {
896                   tree t = tsi_stmt (initially_stmts);
897
898                   tree call = NULL_TREE;
899                   if (TREE_CODE (t) == CALL_EXPR)
900                     call = t;
901                   else if (TREE_CODE (t) == MODIFY_EXPR &&
902                            TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR)
903                     call = TREE_OPERAND (t, 1);
904                   else if (TREE_CODE (t) == TRY_FINALLY_EXPR)
905                     {
906                       /* We hope that this is the try/finally block sometimes
907                          constructed by gimplify_bind_expr() for a BIND_EXPR
908                          that contains VLAs.  This very naive recursion
909                          appears to be sufficient.  */
910                       initially_stmts = tsi_start (TREE_OPERAND (t, 0));
911                     }
912
913                   if (call != NULL_TREE)
914                     {
915                       if (TREE_CODE (TREE_OPERAND(call, 0)) == ADDR_EXPR &&
916                           TREE_OPERAND (TREE_OPERAND (call, 0), 0) ==
917                                 implicit_built_in_decls [BUILT_IN_STACK_ALLOC])
918                         {
919                           tree stack_alloc_args = TREE_OPERAND (call, 1);
920                           tree stack_alloc_op1 = TREE_VALUE (stack_alloc_args);
921                           tree stack_alloc_op2 = TREE_VALUE (TREE_CHAIN (stack_alloc_args));
922                           
923                           if (TREE_CODE (stack_alloc_op1) == ADDR_EXPR &&
924                               TREE_OPERAND (stack_alloc_op1, 0) == decl)
925                             {
926                               /* Got it! */
927                               size = stack_alloc_op2;
928                               stack_alloc_call = call;
929                               /* Advance iterator to point past this allocation call.  */
930                               tsi_next (&initially_stmts);
931                               break;
932                             }
933                         }
934                     }
935
936                   tsi_next (&initially_stmts);
937                 }
938
939               if (stack_alloc_call == NULL_TREE)
940                 {
941                   warning ("mudflap cannot handle variable-sized declaration `%s'",
942                          IDENTIFIER_POINTER (DECL_NAME (decl)));
943                   break;
944                 }
945             }
946           else
947             {
948               size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl)));
949             }
950
951           /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */
952           unregister_fncall_params =
953             tree_cons (NULL_TREE,
954                        convert (ptr_type_node,
955                                 mf_mark (build1 (ADDR_EXPR,
956                                                  build_pointer_type (TREE_TYPE (decl)),
957                                                  decl))),
958                        tree_cons (NULL_TREE, 
959                                   size,
960                                   tree_cons (NULL_TREE, 
961                                              build_int_2 (3, 0), /* __MF_TYPE_STACK */
962                                              NULL_TREE)));
963           /* __mf_unregister (...) */
964           unregister_fncall = build_function_call_expr (mf_unregister_fndecl,
965                                                         unregister_fncall_params);
966
967           /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK, "name") */
968           variable_name = mf_varname_tree (decl);
969           register_fncall_params =
970             tree_cons (NULL_TREE,
971                    convert (ptr_type_node,
972                             mf_mark (build1 (ADDR_EXPR,
973                                              build_pointer_type (TREE_TYPE (decl)),
974                                              decl))),
975                        tree_cons (NULL_TREE,
976                                   size,
977                                   tree_cons (NULL_TREE,
978                                              build_int_2 (3, 0), /* __MF_TYPE_STACK */
979                                              tree_cons (NULL_TREE,
980                                                         variable_name,
981                                                         NULL_TREE))));
982
983           /* __mf_register (...) */
984           register_fncall = build_function_call_expr (mf_register_fndecl,
985                                                       register_fncall_params);
986
987           /* Accumulate the two calls.  */
988           /* ??? Set EXPR_LOCATION.  */
989           gimplify_stmt (&register_fncall);
990           gimplify_stmt (&unregister_fncall);
991
992           /* Add the __mf_register call at the current appending point.  */
993           if (tsi_end_p (initially_stmts))
994             internal_error ("mudflap ran off end of BIND_EXPR body");
995           tsi_link_before (&initially_stmts, register_fncall, TSI_SAME_STMT);
996
997           /* Accumulate the FINALLY piece.  */
998           append_to_statement_list (unregister_fncall, &finally_stmts);
999
1000           mf_mark (decl);
1001         }
1002
1003       decl = TREE_CHAIN (decl);
1004     }
1005
1006   /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */
1007   if (finally_stmts != NULL_TREE)
1008     {
1009       tree t = build (TRY_FINALLY_EXPR, void_type_node,
1010                       *stmt_list, finally_stmts);
1011       *stmt_list = NULL;
1012       append_to_statement_list (t, stmt_list);
1013     }
1014 }
1015
1016
1017 /* Process every variable mentioned in BIND_EXPRs.  */
1018 static tree
1019 mx_xfn_xform_decls (tree *t, int *continue_p, void *data)
1020 {
1021   struct mf_xform_decls_data* d = (struct mf_xform_decls_data*) data;
1022
1023   if (*t == NULL_TREE || *t == error_mark_node)
1024     {
1025       *continue_p = 0;
1026       return NULL_TREE;
1027     }
1028
1029   *continue_p = 1;
1030
1031   switch (TREE_CODE (*t))
1032     {
1033     case BIND_EXPR:
1034       {
1035         /* Process function parameters now (but only once).  */
1036         mx_register_decls (d->param_decls, &BIND_EXPR_BODY (*t));
1037         d->param_decls = NULL_TREE;
1038
1039         mx_register_decls (BIND_EXPR_VARS (*t), &BIND_EXPR_BODY (*t));
1040       }
1041       break;
1042
1043     default:
1044       break;
1045     }
1046
1047   return NULL;
1048 }
1049
1050 /* Perform the object lifetime tracking mudflap transform on the given function
1051    tree.  The tree is mutated in place, with possibly copied subtree nodes.
1052
1053    For every auto variable declared, if its address is ever taken
1054    within the function, then supply its lifetime to the mudflap
1055    runtime with the __mf_register and __mf_unregister calls.
1056 */
1057
1058 static void
1059 mf_xform_decls (tree fnbody, tree fnparams)
1060 {
1061   struct mf_xform_decls_data d;
1062   d.param_decls = fnparams;
1063   walk_tree_without_duplicates (&fnbody, mx_xfn_xform_decls, &d);
1064 }
1065
1066
1067 /* ------------------------------------------------------------------------ */
1068 /* Externally visible mudflap functions.  */
1069
1070
1071 /* Mark and return the given tree node to prevent further mudflap
1072    transforms.  */
1073 static GTY ((param_is (union tree_node))) htab_t marked_trees = NULL;
1074
1075 tree
1076 mf_mark (tree t)
1077 {
1078   void **slot;
1079
1080   if (marked_trees == NULL)
1081     marked_trees = htab_create_ggc (31, htab_hash_pointer, htab_eq_pointer, NULL);
1082
1083   slot = htab_find_slot (marked_trees, t, INSERT);
1084   *slot = t;
1085   return t;
1086 }
1087
1088 int
1089 mf_marked_p (tree t)
1090 {
1091   void *entry;
1092
1093   if (marked_trees == NULL)
1094     return 0;
1095
1096   entry = htab_find (marked_trees, t);
1097   return (entry != NULL);
1098 }
1099
1100 /* Remember given node as a static of some kind: global data,
1101    function-scope static, or an anonymous constant.  Its assembler
1102    label is given.  */
1103
1104 /* A list of globals whose incomplete declarations we encountered.
1105    Instead of emitting the __mf_register call for them here, it's
1106    delayed until program finish time.  If they're still incomplete by
1107    then, warnings are emitted.  */
1108
1109 static GTY (()) varray_type deferred_static_decls;
1110
1111 /* A list of statements for calling __mf_register() at startup time.  */
1112 static GTY (()) tree enqueued_call_stmt_chain;
1113
1114 static void
1115 mudflap_register_call (tree obj, tree object_size, tree varname)
1116 {
1117   tree arg, args, call_stmt;
1118
1119   args = tree_cons (NULL_TREE, varname, NULL_TREE);
1120
1121   arg = build_int_2 (4, 0); /* __MF_TYPE_STATIC */
1122   args = tree_cons (NULL_TREE, arg, args);
1123
1124   arg = convert (size_type_node, object_size);
1125   args = tree_cons (NULL_TREE, arg, args);
1126
1127   arg = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (obj)), obj);
1128   arg = convert (ptr_type_node, arg);
1129   args = tree_cons (NULL_TREE, arg, args);
1130
1131   call_stmt = build_function_call_expr (mf_register_fndecl, args);
1132
1133   append_to_statement_list (call_stmt, &enqueued_call_stmt_chain);
1134 }
1135
1136 void
1137 mudflap_enqueue_decl (tree obj)
1138 {
1139   if (mf_marked_p (obj))
1140     return;
1141
1142   /* We don't need to process variable decls that are internally
1143      generated extern.  If we did, we'd end up with warnings for them
1144      during mudflap_finish_file ().  That would confuse the user,
1145      since the text would refer to variables that don't show up in the
1146      user's source code.  */
1147   if (DECL_P (obj) && DECL_EXTERNAL (obj) && DECL_ARTIFICIAL (obj))
1148     return;
1149
1150   if (COMPLETE_TYPE_P (TREE_TYPE (obj)))
1151     {
1152       tree object_size;
1153
1154       mf_mark (obj);
1155
1156       object_size = size_in_bytes (TREE_TYPE (obj));
1157
1158       if (dump_file)
1159         {
1160           fprintf (dump_file, "enqueue_decl obj=`");
1161           print_generic_expr (dump_file, obj, dump_flags);
1162           fprintf (dump_file, "' size=");
1163           print_generic_expr (dump_file, object_size, dump_flags);
1164           fprintf (dump_file, "\n");
1165         }
1166
1167       /* NB: the above condition doesn't require TREE_USED or
1168          TREE_ADDRESSABLE.  That's because this object may be a global
1169          only used from other compilation units.  XXX: Maybe static
1170          objects could require those attributes being set.  */
1171
1172       mudflap_register_call (obj, object_size, mf_varname_tree (obj));
1173     }
1174   else
1175     {
1176       size_t i;
1177
1178       if (! deferred_static_decls)
1179         VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list");
1180
1181       /* Ugh, linear search... */
1182       for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1183         if (VARRAY_TREE (deferred_static_decls, i) == obj)
1184           {
1185             warning ("mudflap cannot track lifetime of `%s'",
1186                      IDENTIFIER_POINTER (DECL_NAME (obj)));
1187             return;
1188           }
1189
1190       VARRAY_PUSH_TREE (deferred_static_decls, obj);
1191     }
1192 }
1193
1194 void
1195 mudflap_enqueue_constant (tree obj)
1196 {
1197   tree object_size, varname;
1198
1199   if (mf_marked_p (obj))
1200     return;
1201
1202   if (TREE_CODE (obj) == STRING_CST)
1203     object_size = build_int_2 (TREE_STRING_LENGTH (obj), 0);
1204   else
1205     object_size = size_in_bytes (TREE_TYPE (obj));
1206
1207   if (dump_file)
1208     {
1209       fprintf (dump_file, "enqueue_constant obj=`");
1210       print_generic_expr (dump_file, obj, dump_flags);
1211       fprintf (dump_file, "' size=");
1212       print_generic_expr (dump_file, object_size, dump_flags);
1213       fprintf (dump_file, "\n");
1214     }
1215
1216   if (TREE_CODE (obj) == STRING_CST)
1217     varname = mf_build_string ("string literal");
1218   else
1219     varname = mf_build_string ("constant");
1220
1221   mudflap_register_call (obj, object_size, varname);
1222 }
1223
1224
1225 /* Emit any file-wide instrumentation.  */
1226 void
1227 mudflap_finish_file (void)
1228 {
1229   /* Try to give the deferred objects one final try.  */
1230   if (deferred_static_decls)
1231     {
1232       size_t i;
1233
1234       for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1235         {
1236           tree obj = VARRAY_TREE (deferred_static_decls, i);
1237
1238           /* Call enqueue_decl again on the same object it has previously
1239              put into the table.  (It won't modify the table this time, so
1240              infinite iteration is not a problem.)  */
1241           mudflap_enqueue_decl (obj);
1242         }
1243
1244       VARRAY_CLEAR (deferred_static_decls);
1245     }
1246
1247   if (enqueued_call_stmt_chain)
1248     {
1249       cgraph_build_static_cdtor ('I', enqueued_call_stmt_chain);
1250       enqueued_call_stmt_chain = 0;
1251     }
1252 }
1253
1254
1255 static bool
1256 gate_mudflap (void)
1257 {
1258   return flag_mudflap != 0;
1259 }
1260
1261 struct tree_opt_pass pass_mudflap_1 = 
1262 {
1263   "mudflap1",                           /* name */
1264   gate_mudflap,                         /* gate */
1265   execute_mudflap_function_decls,       /* execute */
1266   NULL,                                 /* sub */
1267   NULL,                                 /* next */
1268   0,                                    /* static_pass_number */
1269   0,                                    /* tv_id */
1270   PROP_gimple_any,                      /* properties_required */
1271   0,                                    /* properties_provided */
1272   0,                                    /* properties_destroyed */
1273   0,                                    /* todo_flags_start */
1274   TODO_dump_func                        /* todo_flags_finish */
1275 };
1276
1277 struct tree_opt_pass pass_mudflap_2 = 
1278 {
1279   "mudflap2",                           /* name */
1280   gate_mudflap,                         /* gate */
1281   execute_mudflap_function_ops,         /* execute */
1282   NULL,                                 /* sub */
1283   NULL,                                 /* next */
1284   0,                                    /* static_pass_number */
1285   0,                                    /* tv_id */
1286   PROP_gimple_leh,                      /* properties_required */
1287   0,                                    /* properties_provided */
1288   0,                                    /* properties_destroyed */
1289   0,                                    /* todo_flags_start */
1290   TODO_verify_flow | TODO_verify_stmts
1291   | TODO_dump_func                      /* todo_flags_finish */
1292 };
1293
1294 #include "gt-tree-mudflap.h"