tree-mudflap.c (mx_register_decls): Tolerate decl trees resulting from source code...
[gcc.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"