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>
6 This file is part of GCC.
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
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
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
27 #include "coretypes.h"
29 #include "hard-reg-set.h"
33 #include "basic-block.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"
43 #include "diagnostic.h"
45 #include "langhooks.h"
49 /* Internal function decls */
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
);
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);
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);
69 /* ------------------------------------------------------------------------ */
70 /* Some generally helpful functions for mudflap instrumentation. */
72 /* Build a reference to a literal string. */
74 mf_build_string (const char *string
)
76 size_t len
= strlen (string
);
77 tree result
= mf_mark (build_string (len
+ 1, string
));
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;
87 result
= build1 (ADDR_EXPR
, build_pointer_type (char_type_node
), result
);
89 return mf_mark (result
);
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
98 mf_varname_tree (tree decl
)
100 static pretty_printer buf_rec
;
101 static int initialized
= 0;
102 pretty_printer
*buf
= & buf_rec
;
103 const char *buf_contents
;
106 if (decl
== NULL_TREE
)
111 pp_construct (buf
, /* prefix */ NULL
, /* line-width */ 0);
114 pp_clear_output_area (buf
);
116 /* Add FILENAME[:LINENUMBER]. */
118 expanded_location xloc
= expand_location (DECL_SOURCE_LOCATION (decl
));
119 const char *sourcefile
;
120 unsigned sourceline
= xloc
.line
;
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>";
128 pp_string (buf
, sourcefile
);
132 pp_string (buf
, ":");
133 pp_decimal_int (buf
, sourceline
);
137 if (current_function_decl
!= NULL_TREE
)
139 /* Add (FUNCTION): */
140 pp_string (buf
, " (");
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";
148 pp_string (buf
, funcname
);
150 pp_string (buf
, ") ");
153 pp_string (buf
, " ");
155 /* Add <variable-declaration>, possibly demangled. */
157 const char *declname
= NULL
;
159 if (strcmp ("GNU C++", lang_hooks
.name
) == 0 &&
160 DECL_NAME (decl
) != NULL
)
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
);
168 if (declname
== NULL
)
169 declname
= lang_hooks
.decl_printable_name (decl
, 3);
171 if (declname
== NULL
)
172 declname
= "<unnamed variable>";
174 pp_string (buf
, declname
);
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
);
186 /* And another friend, for producing a simpler message. */
189 mf_file_function_line_tree (location_t location
)
191 expanded_location xloc
= expand_location (location
);
192 const char *file
= NULL
, *colon
, *line
, *op
, *name
, *cp
;
197 /* Add FILENAME[:LINENUMBER]. */
199 if (file
== NULL
&& current_function_decl
!= NULL_TREE
)
200 file
= DECL_SOURCE_FILE (current_function_decl
);
202 file
= "<unknown file>";
206 sprintf (linebuf
, "%d", xloc
.line
);
213 /* Add (FUNCTION). */
214 name
= lang_hooks
.decl_printable_name (current_function_decl
, 1);
223 string
= concat (file
, colon
, line
, op
, name
, cp
, NULL
);
224 result
= mf_build_string (string
);
231 /* global tree nodes */
233 /* Global tree objects for global variables and functions exported by
234 mudflap runtime library. mf_init_extern_trees must be called
235 before using these. */
237 /* uintptr_t (usually "unsigned long") */
238 static GTY (()) tree mf_uintptr_type
;
240 /* struct __mf_cache { uintptr_t low; uintptr_t high; }; */
241 static GTY (()) tree mf_cache_struct_type
;
243 /* struct __mf_cache * const */
244 static GTY (()) tree mf_cache_structptr_type
;
246 /* extern struct __mf_cache __mf_lookup_cache []; */
247 static GTY (()) tree mf_cache_array_decl
;
249 /* extern unsigned char __mf_lc_shift; */
250 static GTY (()) tree mf_cache_shift_decl
;
252 /* extern uintptr_t __mf_lc_mask; */
253 static GTY (()) tree mf_cache_mask_decl
;
255 /* Their function-scope local shadows, used in single-threaded mode only. */
257 /* auto const unsigned char __mf_lc_shift_l; */
258 static GTY (()) tree mf_cache_shift_decl_l
;
260 /* auto const uintptr_t __mf_lc_mask_l; */
261 static GTY (()) tree mf_cache_mask_decl_l
;
263 /* extern void __mf_check (void *ptr, size_t sz, int type, const char *); */
264 static GTY (()) tree mf_check_fndecl
;
266 /* extern void __mf_register (void *ptr, size_t sz, int type, const char *); */
267 static GTY (()) tree mf_register_fndecl
;
269 /* extern void __mf_unregister (void *ptr, size_t sz, int type); */
270 static GTY (()) tree mf_unregister_fndecl
;
272 /* extern void __mf_init (); */
273 static GTY (()) tree mf_init_fndecl
;
275 /* extern int __mf_set_options (const char*); */
276 static GTY (()) tree mf_set_options_fndecl
;
279 /* Helper for mudflap_init: construct a decl with the given category,
280 name, and type, mark it an external reference, and pushdecl it. */
282 mf_make_builtin (enum tree_code category
, const char *name
, tree type
)
284 tree decl
= mf_mark (build_decl (category
, get_identifier (name
), type
));
285 TREE_PUBLIC (decl
) = 1;
286 DECL_EXTERNAL (decl
) = 1;
287 lang_hooks
.decls
.pushdecl (decl
);
291 /* Helper for mudflap_init: construct a tree corresponding to the type
292 struct __mf_cache { uintptr_t low; uintptr_t high; };
293 where uintptr_t is the FIELD_TYPE argument. */
295 mf_make_mf_cache_struct_type (tree field_type
)
297 /* There is, abominably, no language-independent way to construct a
298 RECORD_TYPE. So we have to call the basic type construction
299 primitives by hand. */
300 tree fieldlo
= build_decl (FIELD_DECL
, get_identifier ("low"), field_type
);
301 tree fieldhi
= build_decl (FIELD_DECL
, get_identifier ("high"), field_type
);
303 tree struct_type
= make_node (RECORD_TYPE
);
304 DECL_CONTEXT (fieldlo
) = struct_type
;
305 DECL_CONTEXT (fieldhi
) = struct_type
;
306 TREE_CHAIN (fieldlo
) = fieldhi
;
307 TYPE_FIELDS (struct_type
) = fieldlo
;
308 TYPE_NAME (struct_type
) = get_identifier ("__mf_cache");
309 layout_type (struct_type
);
314 #define build_function_type_0(rtype) \
315 build_function_type (rtype, void_list_node)
316 #define build_function_type_1(rtype, arg1) \
317 build_function_type (rtype, tree_cons (0, arg1, void_list_node))
318 #define build_function_type_3(rtype, arg1, arg2, arg3) \
319 build_function_type (rtype, tree_cons (0, arg1, tree_cons (0, arg2, \
320 tree_cons (0, arg3, void_list_node))))
321 #define build_function_type_4(rtype, arg1, arg2, arg3, arg4) \
322 build_function_type (rtype, tree_cons (0, arg1, tree_cons (0, arg2, \
323 tree_cons (0, arg3, tree_cons (0, arg4, \
326 /* Initialize the global tree nodes that correspond to mf-runtime.h
331 static bool done
= false;
332 tree mf_const_string_type
;
333 tree mf_cache_array_type
;
334 tree mf_check_register_fntype
;
335 tree mf_unregister_fntype
;
337 tree mf_set_options_fntype
;
343 mf_uintptr_type
= lang_hooks
.types
.type_for_mode (ptr_mode
,
346 = build_pointer_type (build_qualified_type
347 (char_type_node
, TYPE_QUAL_CONST
));
349 mf_cache_struct_type
= mf_make_mf_cache_struct_type (mf_uintptr_type
);
350 mf_cache_structptr_type
= build_pointer_type (mf_cache_struct_type
);
351 mf_cache_array_type
= build_array_type (mf_cache_struct_type
, 0);
352 mf_check_register_fntype
=
353 build_function_type_4 (void_type_node
, ptr_type_node
, size_type_node
,
354 integer_type_node
, mf_const_string_type
);
355 mf_unregister_fntype
=
356 build_function_type_3 (void_type_node
, ptr_type_node
, size_type_node
,
359 build_function_type_0 (void_type_node
);
360 mf_set_options_fntype
=
361 build_function_type_1 (integer_type_node
, mf_const_string_type
);
363 mf_cache_array_decl
= mf_make_builtin (VAR_DECL
, "__mf_lookup_cache",
364 mf_cache_array_type
);
365 mf_cache_shift_decl
= mf_make_builtin (VAR_DECL
, "__mf_lc_shift",
366 unsigned_char_type_node
);
367 mf_cache_mask_decl
= mf_make_builtin (VAR_DECL
, "__mf_lc_mask",
369 mf_check_fndecl
= mf_make_builtin (FUNCTION_DECL
, "__mf_check",
370 mf_check_register_fntype
);
371 mf_register_fndecl
= mf_make_builtin (FUNCTION_DECL
, "__mf_register",
372 mf_check_register_fntype
);
373 mf_unregister_fndecl
= mf_make_builtin (FUNCTION_DECL
, "__mf_unregister",
374 mf_unregister_fntype
);
375 mf_init_fndecl
= mf_make_builtin (FUNCTION_DECL
, "__mf_init",
377 mf_set_options_fndecl
= mf_make_builtin (FUNCTION_DECL
, "__mf_set_options",
378 mf_set_options_fntype
);
380 #undef build_function_type_4
381 #undef build_function_type_3
382 #undef build_function_type_1
383 #undef build_function_type_0
386 /* ------------------------------------------------------------------------ */
387 /* Memory reference transforms. Perform the mudflap indirection-related
388 tree transforms on the current function.
390 This is the second part of the mudflap instrumentation. It works on
391 low-level GIMPLE using the CFG, because we want to run this pass after
392 tree optimizations have been performed, but we have to preserve the CFG
393 for expansion from trees to RTL. */
396 execute_mudflap_function_ops (void)
398 if (mf_marked_p (current_function_decl
))
401 push_gimplify_context ();
403 /* In multithreaded mode, don't cache the lookup cache parameters. */
404 if (! flag_mudflap_threads
)
405 mf_decl_cache_locals ();
409 if (! flag_mudflap_threads
)
410 mf_decl_clear_locals ();
412 pop_gimplify_context (NULL
);
415 /* Create and initialize local shadow variables for the lookup cache
416 globals. Put their decls in the *_l globals for use by
417 mf_build_check_statement_for. */
420 mf_decl_cache_locals (void)
422 tree t
, shift_init_stmts
, mask_init_stmts
;
423 tree_stmt_iterator tsi
;
425 /* Build the cache vars. */
426 mf_cache_shift_decl_l
427 = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_shift_decl
),
428 "__mf_lookup_shift_l"));
431 = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_mask_decl
),
432 "__mf_lookup_mask_l"));
434 /* Build initialization nodes for the cache vars. We just load the
435 globals into the cache variables. */
436 t
= build (MODIFY_EXPR
, TREE_TYPE (mf_cache_shift_decl_l
),
437 mf_cache_shift_decl_l
, mf_cache_shift_decl
);
438 SET_EXPR_LOCATION (t
, DECL_SOURCE_LOCATION (current_function_decl
));
439 gimplify_to_stmt_list (&t
);
440 shift_init_stmts
= t
;
442 t
= build (MODIFY_EXPR
, TREE_TYPE (mf_cache_mask_decl_l
),
443 mf_cache_mask_decl_l
, mf_cache_mask_decl
);
444 SET_EXPR_LOCATION (t
, DECL_SOURCE_LOCATION (current_function_decl
));
445 gimplify_to_stmt_list (&t
);
448 /* Anticipating multiple entry points, we insert the cache vars
449 initializers in each successor of the ENTRY_BLOCK_PTR. */
450 for (tsi
= tsi_start (shift_init_stmts
);
453 insert_edge_copies (tsi_stmt (tsi
), ENTRY_BLOCK_PTR
);
455 for (tsi
= tsi_start (mask_init_stmts
);
458 insert_edge_copies (tsi_stmt (tsi
), ENTRY_BLOCK_PTR
);
459 bsi_commit_edge_inserts (NULL
);
464 mf_decl_clear_locals (void)
466 /* Unset local shadows. */
467 mf_cache_shift_decl_l
= NULL_TREE
;
468 mf_cache_mask_decl_l
= NULL_TREE
;
472 mf_build_check_statement_for (tree addr
, tree size
,
473 block_stmt_iterator
*instr_bsi
,
474 location_t
*locus
, tree dirflag
)
476 tree_stmt_iterator head
, tsi
;
477 tree ptrtype
= TREE_TYPE (addr
);
478 block_stmt_iterator bsi
;
479 basic_block cond_bb
, then_bb
, join_bb
;
481 tree cond
, t
, u
, v
, l1
, l2
;
486 /* We first need to split the current basic block, and start altering
487 the CFG. This allows us to insert the statements we're about to
488 construct into the right basic blocks. The label l1 is the label
489 of the block for the THEN clause of the conditional jump we're
490 about to construct, and l2 is the ELSE clause, which is just the
491 continuation of the old statement stream. */
492 l1
= create_artificial_label ();
493 l2
= create_artificial_label ();
494 cond_bb
= bb_for_stmt (bsi_stmt (*instr_bsi
));
497 if (! bsi_end_p (bsi
))
499 e
= split_block (cond_bb
, bsi_stmt (bsi
));
506 cond_bb
= create_empty_bb (join_bb
->prev_bb
);
507 e
= make_edge (cond_bb
, join_bb
, 0);
509 e
->flags
= EDGE_FALSE_VALUE
;
510 then_bb
= create_empty_bb (cond_bb
);
511 make_edge (cond_bb
, then_bb
, EDGE_TRUE_VALUE
);
512 make_edge (then_bb
, join_bb
, EDGE_FALLTHRU
);
514 /* We expect that the conditional jump we will construct will not
515 be taken very often as it basically is an exception condition. */
516 predict_edge_def (then_bb
->pred
, PRED_MUDFLAP
, NOT_TAKEN
);
518 /* Update dominance info. Note that bb_join's data was
519 updated by split_block. */
520 if (dom_computed
[CDI_DOMINATORS
] >= DOM_CONS_OK
)
522 set_immediate_dominator (CDI_DOMINATORS
, then_bb
, cond_bb
);
523 set_immediate_dominator (CDI_DOMINATORS
, join_bb
, cond_bb
);
526 /* Build our local variables. */
527 mf_value
= create_tmp_var (ptrtype
, "__mf_value");
528 mf_elem
= create_tmp_var (mf_cache_structptr_type
, "__mf_elem");
529 mf_base
= create_tmp_var (mf_uintptr_type
, "__mf_base");
531 /* Build: __mf_value = <address expression>. */
532 t
= build (MODIFY_EXPR
, void_type_node
, mf_value
, unshare_expr (addr
));
533 SET_EXPR_LOCUS (t
, locus
);
534 gimplify_to_stmt_list (&t
);
535 head
= tsi_start (t
);
538 /* Build: __mf_base = (uintptr_t)__mf_value. */
539 t
= build (MODIFY_EXPR
, void_type_node
, mf_base
,
540 build1 (NOP_EXPR
, mf_uintptr_type
, mf_value
));
541 SET_EXPR_LOCUS (t
, locus
);
542 gimplify_to_stmt_list (&t
);
543 tsi_link_after (&tsi
, t
, TSI_CONTINUE_LINKING
);
545 /* Build: __mf_elem = &__mf_lookup_cache [(__mf_base >> __mf_shift)
547 t
= build (RSHIFT_EXPR
, mf_uintptr_type
, mf_base
,
548 (flag_mudflap_threads
? mf_cache_shift_decl
: mf_cache_shift_decl_l
));
549 t
= build (BIT_AND_EXPR
, mf_uintptr_type
, t
,
550 (flag_mudflap_threads
? mf_cache_mask_decl
: mf_cache_mask_decl_l
));
551 t
= build (ARRAY_REF
,
552 TREE_TYPE (TREE_TYPE (mf_cache_array_decl
)),
553 mf_cache_array_decl
, t
, NULL_TREE
, NULL_TREE
);
554 t
= build1 (ADDR_EXPR
, mf_cache_structptr_type
, t
);
555 t
= build (MODIFY_EXPR
, void_type_node
, mf_elem
, t
);
556 SET_EXPR_LOCUS (t
, locus
);
557 gimplify_to_stmt_list (&t
);
558 tsi_link_after (&tsi
, t
, TSI_CONTINUE_LINKING
);
560 /* Quick validity check.
562 if (__mf_elem->low > __mf_base
563 || (__mf_elem_high < __mf_base + sizeof(T) - 1))
566 ... and only if single-threaded:
567 __mf_lookup_shift_1 = f...;
568 __mf_lookup_mask_l = ...;
571 It is expected that this body of code is rarely executed so we mark
572 the edge to the THEN clause of the conditional jump as unlikely. */
574 /* Construct t <-- '__mf_elem->low > __mf_base'. */
575 t
= build (COMPONENT_REF
, mf_uintptr_type
,
576 build1 (INDIRECT_REF
, mf_cache_struct_type
, mf_elem
),
577 TYPE_FIELDS (mf_cache_struct_type
), NULL_TREE
);
578 t
= build (GT_EXPR
, boolean_type_node
, t
, mf_base
);
580 /* Construct '__mf_elem->high < __mf_base + sizeof(T) - 1'.
583 1) u <-- '__mf_elem->high'
584 2) v <-- '__mf_base + sizeof (T) - 1'.
586 Then build 'u <-- (u < v). */
589 u
= build (COMPONENT_REF
, mf_uintptr_type
,
590 build1 (INDIRECT_REF
, mf_cache_struct_type
, mf_elem
),
591 TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type
)), NULL_TREE
);
593 v
= convert (mf_uintptr_type
,
594 size_binop (MINUS_EXPR
, size
, size_one_node
));
595 v
= fold (build (PLUS_EXPR
, mf_uintptr_type
, mf_base
, v
));
597 u
= build (LT_EXPR
, boolean_type_node
, u
, v
);
599 /* Build the composed conditional: t <-- 't || u'. Then store the
600 result of the evaluation of 't' in a temporary variable which we
601 can use as the condition for the conditional jump. */
602 t
= build (TRUTH_OR_EXPR
, boolean_type_node
, t
, u
);
603 cond
= create_tmp_var (boolean_type_node
, "__mf_unlikely_cond");
604 t
= build (MODIFY_EXPR
, boolean_type_node
, cond
, t
);
605 gimplify_to_stmt_list (&t
);
606 tsi_link_after (&tsi
, t
, TSI_CONTINUE_LINKING
);
608 /* Build the conditional jump. 'cond' is just a temporary so we can
609 simply build a void COND_EXPR. We do need labels in both arms though. */
610 t
= build (COND_EXPR
, void_type_node
, cond
,
611 build (GOTO_EXPR
, void_type_node
, tree_block_label (then_bb
)),
612 build (GOTO_EXPR
, void_type_node
, tree_block_label (join_bb
)));
613 SET_EXPR_LOCUS (t
, locus
);
614 tsi_link_after (&tsi
, t
, TSI_CONTINUE_LINKING
);
616 /* At this point, after so much hard work, we have only constructed
617 the conditional jump,
619 if (__mf_elem->low > __mf_base
620 || (__mf_elem_high < __mf_base + sizeof(T) - 1))
622 The lowered GIMPLE tree representing this code is in the statement
623 list starting at 'head'.
625 We can insert this now in the current basic block, ie. the one that
626 the statement we're instrumenting was originally in. */
627 bsi
= bsi_last (cond_bb
);
628 for (tsi
= head
; ! tsi_end_p (tsi
); tsi_next (&tsi
))
629 bsi_insert_after (&bsi
, tsi_stmt (tsi
), BSI_CONTINUE_LINKING
);
631 /* Now build up the body of the cache-miss handling:
636 This is the body of the conditional. */
638 u
= tree_cons (NULL_TREE
,
639 mf_file_function_line_tree (locus
== NULL
? UNKNOWN_LOCATION
642 u
= tree_cons (NULL_TREE
, dirflag
, u
);
643 u
= tree_cons (NULL_TREE
, size
, u
);
644 u
= tree_cons (NULL_TREE
, mf_value
, u
);
645 t
= build_function_call_expr (mf_check_fndecl
, u
);
646 gimplify_to_stmt_list (&t
);
647 head
= tsi_start (t
);
650 if (! flag_mudflap_threads
)
652 t
= build (MODIFY_EXPR
, void_type_node
,
653 mf_cache_shift_decl_l
, mf_cache_shift_decl
);
654 tsi_link_after (&tsi
, t
, TSI_CONTINUE_LINKING
);
656 t
= build (MODIFY_EXPR
, void_type_node
,
657 mf_cache_mask_decl_l
, mf_cache_mask_decl
);
658 tsi_link_after (&tsi
, t
, TSI_CONTINUE_LINKING
);
661 /* Insert the check code in the THEN block. */
662 bsi
= bsi_start (then_bb
);
663 for (tsi
= head
; ! tsi_end_p (tsi
); tsi_next (&tsi
))
664 bsi_insert_after (&bsi
, tsi_stmt (tsi
), BSI_CONTINUE_LINKING
);
666 *instr_bsi
= bsi_start (join_bb
);
667 bsi_next (instr_bsi
);
671 mf_xform_derefs_1 (block_stmt_iterator
*iter
, tree
*tp
,
672 location_t
*locus
, tree dirflag
)
674 tree type
, ptr_type
, addr
, size
, t
;
676 /* Don't instrument read operations. */
677 if (dirflag
== integer_zero_node
&& flag_mudflap_ignore_reads
)
681 type
= TREE_TYPE (t
);
682 size
= TYPE_SIZE_UNIT (type
);
684 switch (TREE_CODE (t
))
688 /* Omit checking if we can statically determine that the access is
689 valid. For non-addressable local arrays this is not optional,
690 since we won't have called __mf_register for the object. */
693 op0
= TREE_OPERAND (t
, 0);
694 op1
= TREE_OPERAND (t
, 1);
695 while (TREE_CODE (op1
) == INTEGER_CST
)
697 tree dom
= TYPE_DOMAIN (TREE_TYPE (op0
));
699 /* Test for index in range. Break if not. */
701 || (! TYPE_MIN_VALUE (dom
)
702 || ! really_constant_p (TYPE_MIN_VALUE (dom
)))
703 || (! TYPE_MAX_VALUE (dom
)
704 || ! really_constant_p (TYPE_MAX_VALUE (dom
)))
705 || (tree_int_cst_lt (op1
, TYPE_MIN_VALUE (dom
))
706 || tree_int_cst_lt (TYPE_MAX_VALUE (dom
), op1
)))
709 /* If we're looking at a non-external VAR_DECL, then the
710 access must be ok. */
711 if (TREE_CODE (op0
) == VAR_DECL
&& !DECL_EXTERNAL (op0
))
714 /* Only continue if we're still looking at an array. */
715 if (TREE_CODE (op0
) != ARRAY_REF
)
718 op1
= TREE_OPERAND (op0
, 1);
719 op0
= TREE_OPERAND (op0
, 0);
722 /* If we got here, we couldn't statically the check. */
723 ptr_type
= build_pointer_type (type
);
724 addr
= build1 (ADDR_EXPR
, ptr_type
, t
);
729 addr
= TREE_OPERAND (t
, 0);
730 ptr_type
= TREE_TYPE (addr
);
733 case ARRAY_RANGE_REF
:
734 warning ("mudflap checking not yet implemented for ARRAY_RANGE_REF");
741 /* If we're not dereferencing something, then the access
743 if (TREE_CODE (TREE_OPERAND (t
, 0)) != INDIRECT_REF
)
746 field
= TREE_OPERAND (t
, 1);
748 /* If we're looking at a bit field, then we can't take its address
749 with ADDR_EXPR -- lang_hooks.mark_addressable will error. Do
750 things the hard way with PLUS. */
751 if (DECL_BIT_FIELD_TYPE (field
))
753 if (TREE_CODE (DECL_SIZE_UNIT (field
)) == INTEGER_CST
)
754 size
= DECL_SIZE_UNIT (field
);
756 addr
= TREE_OPERAND (TREE_OPERAND (t
, 0), 0);
757 addr
= fold_convert (ptr_type_node
, addr
);
758 addr
= fold (build (PLUS_EXPR
, ptr_type_node
,
759 addr
, fold_convert (ptr_type_node
,
760 byte_position (field
))));
764 ptr_type
= build_pointer_type (type
);
765 addr
= build1 (ADDR_EXPR
, ptr_type
, t
);
774 /* If we're not dereferencing something, then the access
776 if (TREE_CODE (TREE_OPERAND (t
, 0)) != INDIRECT_REF
)
779 bpu
= bitsize_int (BITS_PER_UNIT
);
780 ofs
= convert (bitsizetype
, TREE_OPERAND (t
, 2));
781 rem
= size_binop (TRUNC_MOD_EXPR
, ofs
, bpu
);
782 ofs
= size_binop (TRUNC_DIV_EXPR
, ofs
, bpu
);
784 size
= convert (bitsizetype
, TREE_OPERAND (t
, 1));
785 size
= size_binop (PLUS_EXPR
, size
, rem
);
786 size
= size_binop (CEIL_DIV_EXPR
, size
, bpu
);
787 size
= convert (sizetype
, size
);
789 addr
= TREE_OPERAND (TREE_OPERAND (t
, 0), 0);
790 addr
= convert (ptr_type_node
, addr
);
791 addr
= fold (build (PLUS_EXPR
, ptr_type_node
, addr
, ofs
));
799 mf_build_check_statement_for (addr
, size
, iter
, locus
, dirflag
);
803 mf_xform_derefs (void)
805 basic_block bb
, next
;
806 block_stmt_iterator i
;
807 int saved_last_basic_block
= last_basic_block
;
809 bb
= ENTRY_BLOCK_PTR
->next_bb
;
813 for (i
= bsi_start (bb
); !bsi_end_p (i
); bsi_next (&i
))
815 tree s
= bsi_stmt (i
);
817 /* Only a few GIMPLE statements can reference memory. */
818 switch (TREE_CODE (s
))
821 mf_xform_derefs_1 (&i
, &TREE_OPERAND (s
, 0), EXPR_LOCUS (s
),
823 mf_xform_derefs_1 (&i
, &TREE_OPERAND (s
, 1), EXPR_LOCUS (s
),
828 if (TREE_OPERAND (s
, 0) != NULL_TREE
)
830 if (TREE_CODE (TREE_OPERAND (s
, 0)) == MODIFY_EXPR
)
831 mf_xform_derefs_1 (&i
, &TREE_OPERAND (TREE_OPERAND (s
, 0), 1),
832 EXPR_LOCUS (s
), integer_zero_node
);
834 mf_xform_derefs_1 (&i
, &TREE_OPERAND (s
, 0), EXPR_LOCUS (s
),
845 while (bb
&& bb
->index
<= saved_last_basic_block
);
848 /* ------------------------------------------------------------------------ */
849 /* ADDR_EXPR transforms. Perform the declaration-related mudflap tree
850 transforms on the current function.
852 This is the first part of the mudflap instrumentation. It works on
853 high-level GIMPLE because after lowering, all variables are moved out
854 of their BIND_EXPR binding context, and we lose liveness information
855 for the declarations we wish to instrument. */
858 execute_mudflap_function_decls (void)
860 if (mf_marked_p (current_function_decl
))
863 push_gimplify_context ();
865 mf_xform_decls (DECL_SAVED_TREE (current_function_decl
),
866 DECL_ARGUMENTS (current_function_decl
));
868 pop_gimplify_context (NULL
);
871 /* This struct is passed between mf_xform_decls to store state needed
872 during the traversal searching for objects that have their
874 struct mf_xform_decls_data
880 /* Synthesize a CALL_EXPR and a TRY_FINALLY_EXPR, for this chain of
881 _DECLs if appropriate. Arrange to call the __mf_register function
882 now, and the __mf_unregister function later for each. */
884 mx_register_decls (tree decl
, tree
*stmt_list
)
886 tree finally_stmts
= NULL_TREE
;
887 tree_stmt_iterator initially_stmts
= tsi_start (*stmt_list
);
889 while (decl
!= NULL_TREE
)
892 if ((TREE_CODE (decl
) == VAR_DECL
|| TREE_CODE (decl
) == PARM_DECL
)
893 /* It must be a non-external, automatic variable. */
894 && ! DECL_EXTERNAL (decl
)
895 && ! TREE_STATIC (decl
)
896 /* The decl must have its address taken. */
897 && TREE_ADDRESSABLE (decl
)
898 /* The type of the variable must be complete. */
899 && COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl
))
900 /* The decl hasn't been decomposed somehow. */
901 && DECL_VALUE_EXPR (decl
) == NULL
902 /* Don't process the same decl twice. */
903 && ! mf_marked_p (decl
))
905 tree size
= NULL_TREE
, variable_name
;
906 tree unregister_fncall
, unregister_fncall_params
;
907 tree register_fncall
, register_fncall_params
;
909 size
= convert (size_type_node
, TYPE_SIZE_UNIT (TREE_TYPE (decl
)));
911 /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */
912 unregister_fncall_params
=
913 tree_cons (NULL_TREE
,
914 convert (ptr_type_node
,
915 mf_mark (build1 (ADDR_EXPR
,
916 build_pointer_type (TREE_TYPE (decl
)),
918 tree_cons (NULL_TREE
,
920 tree_cons (NULL_TREE
,
921 build_int_2 (3, 0), /* __MF_TYPE_STACK */
923 /* __mf_unregister (...) */
924 unregister_fncall
= build_function_call_expr (mf_unregister_fndecl
,
925 unregister_fncall_params
);
927 /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK, "name") */
928 variable_name
= mf_varname_tree (decl
);
929 register_fncall_params
=
930 tree_cons (NULL_TREE
,
931 convert (ptr_type_node
,
932 mf_mark (build1 (ADDR_EXPR
,
933 build_pointer_type (TREE_TYPE (decl
)),
935 tree_cons (NULL_TREE
,
937 tree_cons (NULL_TREE
,
938 build_int_2 (3, 0), /* __MF_TYPE_STACK */
939 tree_cons (NULL_TREE
,
943 /* __mf_register (...) */
944 register_fncall
= build_function_call_expr (mf_register_fndecl
,
945 register_fncall_params
);
947 /* Accumulate the two calls. */
948 /* ??? Set EXPR_LOCATION. */
949 gimplify_stmt (®ister_fncall
);
950 gimplify_stmt (&unregister_fncall
);
952 /* Add the __mf_register call at the current appending point. */
953 if (tsi_end_p (initially_stmts
))
954 internal_error ("mudflap ran off end of BIND_EXPR body");
955 tsi_link_before (&initially_stmts
, register_fncall
, TSI_SAME_STMT
);
957 /* Accumulate the FINALLY piece. */
958 append_to_statement_list (unregister_fncall
, &finally_stmts
);
963 decl
= TREE_CHAIN (decl
);
966 /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */
967 if (finally_stmts
!= NULL_TREE
)
969 tree t
= build (TRY_FINALLY_EXPR
, void_type_node
,
970 *stmt_list
, finally_stmts
);
972 append_to_statement_list (t
, stmt_list
);
977 /* Process every variable mentioned in BIND_EXPRs. */
979 mx_xfn_xform_decls (tree
*t
, int *continue_p
, void *data
)
981 struct mf_xform_decls_data
* d
= (struct mf_xform_decls_data
*) data
;
983 if (*t
== NULL_TREE
|| *t
== error_mark_node
)
991 switch (TREE_CODE (*t
))
995 /* Process function parameters now (but only once). */
996 mx_register_decls (d
->param_decls
, &BIND_EXPR_BODY (*t
));
997 d
->param_decls
= NULL_TREE
;
999 mx_register_decls (BIND_EXPR_VARS (*t
), &BIND_EXPR_BODY (*t
));
1010 /* Perform the object lifetime tracking mudflap transform on the given function
1011 tree. The tree is mutated in place, with possibly copied subtree nodes.
1013 For every auto variable declared, if its address is ever taken
1014 within the function, then supply its lifetime to the mudflap
1015 runtime with the __mf_register and __mf_unregister calls.
1019 mf_xform_decls (tree fnbody
, tree fnparams
)
1021 struct mf_xform_decls_data d
;
1022 d
.param_decls
= fnparams
;
1023 walk_tree_without_duplicates (&fnbody
, mx_xfn_xform_decls
, &d
);
1027 /* ------------------------------------------------------------------------ */
1028 /* Externally visible mudflap functions. */
1031 /* Mark and return the given tree node to prevent further mudflap
1033 static GTY ((param_is (union tree_node
))) htab_t marked_trees
= NULL
;
1040 if (marked_trees
== NULL
)
1041 marked_trees
= htab_create_ggc (31, htab_hash_pointer
, htab_eq_pointer
, NULL
);
1043 slot
= htab_find_slot (marked_trees
, t
, INSERT
);
1049 mf_marked_p (tree t
)
1053 if (marked_trees
== NULL
)
1056 entry
= htab_find (marked_trees
, t
);
1057 return (entry
!= NULL
);
1060 /* Remember given node as a static of some kind: global data,
1061 function-scope static, or an anonymous constant. Its assembler
1064 /* A list of globals whose incomplete declarations we encountered.
1065 Instead of emitting the __mf_register call for them here, it's
1066 delayed until program finish time. If they're still incomplete by
1067 then, warnings are emitted. */
1069 static GTY (()) varray_type deferred_static_decls
;
1071 /* A list of statements for calling __mf_register() at startup time. */
1072 static GTY (()) tree enqueued_call_stmt_chain
;
1075 mudflap_register_call (tree obj
, tree object_size
, tree varname
)
1077 tree arg
, args
, call_stmt
;
1079 args
= tree_cons (NULL_TREE
, varname
, NULL_TREE
);
1081 arg
= build_int_2 (4, 0); /* __MF_TYPE_STATIC */
1082 args
= tree_cons (NULL_TREE
, arg
, args
);
1084 arg
= convert (size_type_node
, object_size
);
1085 args
= tree_cons (NULL_TREE
, arg
, args
);
1087 arg
= build1 (ADDR_EXPR
, build_pointer_type (TREE_TYPE (obj
)), obj
);
1088 arg
= convert (ptr_type_node
, arg
);
1089 args
= tree_cons (NULL_TREE
, arg
, args
);
1091 call_stmt
= build_function_call_expr (mf_register_fndecl
, args
);
1093 append_to_statement_list (call_stmt
, &enqueued_call_stmt_chain
);
1097 mudflap_enqueue_decl (tree obj
)
1099 if (mf_marked_p (obj
))
1102 /* We don't need to process variable decls that are internally
1103 generated extern. If we did, we'd end up with warnings for them
1104 during mudflap_finish_file (). That would confuse the user,
1105 since the text would refer to variables that don't show up in the
1106 user's source code. */
1107 if (DECL_P (obj
) && DECL_EXTERNAL (obj
) && DECL_ARTIFICIAL (obj
))
1110 if (COMPLETE_TYPE_P (TREE_TYPE (obj
)))
1116 object_size
= size_in_bytes (TREE_TYPE (obj
));
1120 fprintf (dump_file
, "enqueue_decl obj=`");
1121 print_generic_expr (dump_file
, obj
, dump_flags
);
1122 fprintf (dump_file
, "' size=");
1123 print_generic_expr (dump_file
, object_size
, dump_flags
);
1124 fprintf (dump_file
, "\n");
1127 /* NB: the above condition doesn't require TREE_USED or
1128 TREE_ADDRESSABLE. That's because this object may be a global
1129 only used from other compilation units. XXX: Maybe static
1130 objects could require those attributes being set. */
1132 mudflap_register_call (obj
, object_size
, mf_varname_tree (obj
));
1138 if (! deferred_static_decls
)
1139 VARRAY_TREE_INIT (deferred_static_decls
, 10, "deferred static list");
1141 /* Ugh, linear search... */
1142 for (i
= 0; i
< VARRAY_ACTIVE_SIZE (deferred_static_decls
); i
++)
1143 if (VARRAY_TREE (deferred_static_decls
, i
) == obj
)
1145 warning ("mudflap cannot track lifetime of `%s'",
1146 IDENTIFIER_POINTER (DECL_NAME (obj
)));
1150 VARRAY_PUSH_TREE (deferred_static_decls
, obj
);
1155 mudflap_enqueue_constant (tree obj
)
1157 tree object_size
, varname
;
1159 if (mf_marked_p (obj
))
1162 if (TREE_CODE (obj
) == STRING_CST
)
1163 object_size
= build_int_2 (TREE_STRING_LENGTH (obj
), 0);
1165 object_size
= size_in_bytes (TREE_TYPE (obj
));
1169 fprintf (dump_file
, "enqueue_constant obj=`");
1170 print_generic_expr (dump_file
, obj
, dump_flags
);
1171 fprintf (dump_file
, "' size=");
1172 print_generic_expr (dump_file
, object_size
, dump_flags
);
1173 fprintf (dump_file
, "\n");
1176 if (TREE_CODE (obj
) == STRING_CST
)
1177 varname
= mf_build_string ("string literal");
1179 varname
= mf_build_string ("constant");
1181 mudflap_register_call (obj
, object_size
, varname
);
1185 /* Emit any file-wide instrumentation. */
1187 mudflap_finish_file (void)
1189 tree ctor_statements
= NULL_TREE
;
1191 /* Try to give the deferred objects one final try. */
1192 if (deferred_static_decls
)
1196 for (i
= 0; i
< VARRAY_ACTIVE_SIZE (deferred_static_decls
); i
++)
1198 tree obj
= VARRAY_TREE (deferred_static_decls
, i
);
1200 /* Call enqueue_decl again on the same object it has previously
1201 put into the table. (It won't modify the table this time, so
1202 infinite iteration is not a problem.) */
1203 mudflap_enqueue_decl (obj
);
1206 VARRAY_CLEAR (deferred_static_decls
);
1209 /* Insert a call to __mf_init. */
1211 tree call2_stmt
= build_function_call_expr (mf_init_fndecl
, NULL_TREE
);
1212 append_to_statement_list (call2_stmt
, &ctor_statements
);
1215 /* If appropriate, call __mf_set_options to pass along read-ignore mode. */
1216 if (flag_mudflap_ignore_reads
)
1218 tree arg
= tree_cons (NULL_TREE
,
1219 mf_build_string ("-ignore-reads"), NULL_TREE
);
1220 tree call_stmt
= build_function_call_expr (mf_set_options_fndecl
, arg
);
1221 append_to_statement_list (call_stmt
, &ctor_statements
);
1224 /* Append all the enqueued registration calls. */
1225 if (enqueued_call_stmt_chain
)
1227 append_to_statement_list (enqueued_call_stmt_chain
, &ctor_statements
);
1228 enqueued_call_stmt_chain
= NULL_TREE
;
1231 cgraph_build_static_cdtor ('I', ctor_statements
,
1232 MAX_RESERVED_INIT_PRIORITY
-1);
1239 return flag_mudflap
!= 0;
1242 struct tree_opt_pass pass_mudflap_1
=
1244 "mudflap1", /* name */
1245 gate_mudflap
, /* gate */
1246 execute_mudflap_function_decls
, /* execute */
1249 0, /* static_pass_number */
1251 PROP_gimple_any
, /* properties_required */
1252 0, /* properties_provided */
1253 0, /* properties_destroyed */
1254 0, /* todo_flags_start */
1255 TODO_dump_func
/* todo_flags_finish */
1258 struct tree_opt_pass pass_mudflap_2
=
1260 "mudflap2", /* name */
1261 gate_mudflap
, /* gate */
1262 execute_mudflap_function_ops
, /* execute */
1265 0, /* static_pass_number */
1267 PROP_gimple_leh
, /* properties_required */
1268 0, /* properties_provided */
1269 0, /* properties_destroyed */
1270 0, /* todo_flags_start */
1271 TODO_verify_flow
| TODO_verify_stmts
1272 | TODO_dump_func
/* todo_flags_finish */
1275 #include "gt-tree-mudflap.h"