]> gcc.gnu.org Git - gcc.git/blob - gcc/tree-mudflap.c
builtins.def (BUILT_IN_STACK_ALLOC): Remove.
[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 "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 file = xloc.file;
199 if (file == NULL && current_function_decl != NULL_TREE)
200 file = DECL_SOURCE_FILE (current_function_decl);
201 if (file == NULL)
202 file = "<unknown file>";
203
204 if (xloc.line > 0)
205 {
206 sprintf (linebuf, "%d", xloc.line);
207 colon = ":";
208 line = linebuf;
209 }
210 else
211 colon = line = "";
212
213 /* Add (FUNCTION). */
214 name = lang_hooks.decl_printable_name (current_function_decl, 1);
215 if (name)
216 {
217 op = " (";
218 cp = ")";
219 }
220 else
221 op = name = cp = "";
222
223 string = concat (file, colon, line, op, name, cp, NULL);
224 result = mf_build_string (string);
225 free (string);
226
227 return result;
228 }
229
230
231 /* global tree nodes */
232
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. */
236
237 /* uintptr_t (usually "unsigned long") */
238 static GTY (()) tree mf_uintptr_type;
239
240 /* struct __mf_cache { uintptr_t low; uintptr_t high; }; */
241 static GTY (()) tree mf_cache_struct_type;
242
243 /* struct __mf_cache * const */
244 static GTY (()) tree mf_cache_structptr_type;
245
246 /* extern struct __mf_cache __mf_lookup_cache []; */
247 static GTY (()) tree mf_cache_array_decl;
248
249 /* extern unsigned char __mf_lc_shift; */
250 static GTY (()) tree mf_cache_shift_decl;
251
252 /* extern uintptr_t __mf_lc_mask; */
253 static GTY (()) tree mf_cache_mask_decl;
254
255 /* Their function-scope local shadows, used in single-threaded mode only. */
256
257 /* auto const unsigned char __mf_lc_shift_l; */
258 static GTY (()) tree mf_cache_shift_decl_l;
259
260 /* auto const uintptr_t __mf_lc_mask_l; */
261 static GTY (()) tree mf_cache_mask_decl_l;
262
263 /* extern void __mf_check (void *ptr, size_t sz, int type, const char *); */
264 static GTY (()) tree mf_check_fndecl;
265
266 /* extern void __mf_register (void *ptr, size_t sz, int type, const char *); */
267 static GTY (()) tree mf_register_fndecl;
268
269 /* extern void __mf_unregister (void *ptr, size_t sz, int type); */
270 static GTY (()) tree mf_unregister_fndecl;
271
272 /* extern void __mf_init (); */
273 static GTY (()) tree mf_init_fndecl;
274
275 /* extern int __mf_set_options (const char*); */
276 static GTY (()) tree mf_set_options_fndecl;
277
278
279 /* Helper for mudflap_init: construct a decl with the given category,
280 name, and type, mark it an external reference, and pushdecl it. */
281 static inline tree
282 mf_make_builtin (enum tree_code category, const char *name, tree type)
283 {
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);
288 return decl;
289 }
290
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. */
294 static inline tree
295 mf_make_mf_cache_struct_type (tree field_type)
296 {
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);
302
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);
310
311 return struct_type;
312 }
313
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, \
324 void_list_node)))))
325
326 /* Initialize the global tree nodes that correspond to mf-runtime.h
327 declarations. */
328 void
329 mudflap_init (void)
330 {
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;
336 tree mf_init_fntype;
337 tree mf_set_options_fntype;
338
339 if (done)
340 return;
341 done = true;
342
343 mf_uintptr_type = lang_hooks.types.type_for_mode (ptr_mode,
344 /*unsignedp=*/true);
345 mf_const_string_type
346 = build_pointer_type (build_qualified_type
347 (char_type_node, TYPE_QUAL_CONST));
348
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,
357 integer_type_node);
358 mf_init_fntype =
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);
362
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",
368 mf_uintptr_type);
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",
376 mf_init_fntype);
377 mf_set_options_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_set_options",
378 mf_set_options_fntype);
379 }
380 #undef build_function_type_4
381 #undef build_function_type_3
382 #undef build_function_type_1
383 #undef build_function_type_0
384
385
386 /* ------------------------------------------------------------------------ */
387 /* Memory reference transforms. Perform the mudflap indirection-related
388 tree transforms on the current function.
389
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. */
394
395 static void
396 execute_mudflap_function_ops (void)
397 {
398 if (mf_marked_p (current_function_decl))
399 return;
400
401 push_gimplify_context ();
402
403 /* In multithreaded mode, don't cache the lookup cache parameters. */
404 if (! flag_mudflap_threads)
405 mf_decl_cache_locals ();
406
407 mf_xform_derefs ();
408
409 if (! flag_mudflap_threads)
410 mf_decl_clear_locals ();
411
412 pop_gimplify_context (NULL);
413 }
414
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. */
418
419 static void
420 mf_decl_cache_locals (void)
421 {
422 tree t, shift_init_stmts, mask_init_stmts;
423 tree_stmt_iterator tsi;
424
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"));
429
430 mf_cache_mask_decl_l
431 = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_mask_decl),
432 "__mf_lookup_mask_l"));
433
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;
441
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);
446 mask_init_stmts = t;
447
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);
451 ! tsi_end_p (tsi);
452 tsi_next (&tsi))
453 insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR);
454
455 for (tsi = tsi_start (mask_init_stmts);
456 ! tsi_end_p (tsi);
457 tsi_next (&tsi))
458 insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR);
459 bsi_commit_edge_inserts (NULL);
460 }
461
462
463 static void
464 mf_decl_clear_locals (void)
465 {
466 /* Unset local shadows. */
467 mf_cache_shift_decl_l = NULL_TREE;
468 mf_cache_mask_decl_l = NULL_TREE;
469 }
470
471 static void
472 mf_build_check_statement_for (tree addr, tree size,
473 block_stmt_iterator *instr_bsi,
474 location_t *locus, tree dirflag)
475 {
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;
480 edge e;
481 tree cond, t, u, v, l1, l2;
482 tree mf_value;
483 tree mf_base;
484 tree mf_elem;
485
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));
495 bsi = *instr_bsi;
496 bsi_prev (&bsi);
497 if (! bsi_end_p (bsi))
498 {
499 e = split_block (cond_bb, bsi_stmt (bsi));
500 cond_bb = e->src;
501 join_bb = e->dest;
502 }
503 else
504 {
505 join_bb = cond_bb;
506 cond_bb = create_empty_bb (join_bb->prev_bb);
507 e = make_edge (cond_bb, join_bb, 0);
508 }
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);
513
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);
517
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)
521 {
522 set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
523 set_immediate_dominator (CDI_DOMINATORS, join_bb, cond_bb);
524 }
525
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");
530
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);
536 tsi = tsi_last (t);
537
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);
544
545 /* Build: __mf_elem = &__mf_lookup_cache [(__mf_base >> __mf_shift)
546 & __mf_mask]. */
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);
559
560 /* Quick validity check.
561
562 if (__mf_elem->low > __mf_base
563 || (__mf_elem_high < __mf_base + sizeof(T) - 1))
564 {
565 __mf_check ();
566 ... and only if single-threaded:
567 __mf_lookup_shift_1 = f...;
568 __mf_lookup_mask_l = ...;
569 }
570
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. */
573
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);
579
580 /* Construct '__mf_elem->high < __mf_base + sizeof(T) - 1'.
581
582 First build:
583 1) u <-- '__mf_elem->high'
584 2) v <-- '__mf_base + sizeof (T) - 1'.
585
586 Then build 'u <-- (u < v). */
587
588
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);
592
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));
596
597 u = build (LT_EXPR, boolean_type_node, u, v);
598
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);
607
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);
615
616 /* At this point, after so much hard work, we have only constructed
617 the conditional jump,
618
619 if (__mf_elem->low > __mf_base
620 || (__mf_elem_high < __mf_base + sizeof(T) - 1))
621
622 The lowered GIMPLE tree representing this code is in the statement
623 list starting at 'head'.
624
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);
630
631 /* Now build up the body of the cache-miss handling:
632
633 __mf_check();
634 refresh *_l vars.
635
636 This is the body of the conditional. */
637
638 u = tree_cons (NULL_TREE,
639 mf_file_function_line_tree (locus == NULL ? UNKNOWN_LOCATION
640 : *locus),
641 NULL_TREE);
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);
648 tsi = tsi_last (t);
649
650 if (! flag_mudflap_threads)
651 {
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);
655
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);
659 }
660
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);
665
666 *instr_bsi = bsi_start (join_bb);
667 bsi_next (instr_bsi);
668 }
669
670 static void
671 mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp,
672 location_t *locus, tree dirflag)
673 {
674 tree type, ptr_type, addr, size, t;
675
676 /* Don't instrument read operations. */
677 if (dirflag == integer_zero_node && flag_mudflap_ignore_reads)
678 return;
679
680 t = *tp;
681 type = TREE_TYPE (t);
682 size = TYPE_SIZE_UNIT (type);
683
684 switch (TREE_CODE (t))
685 {
686 case ARRAY_REF:
687 {
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. */
691 tree op0, op1;
692
693 op0 = TREE_OPERAND (t, 0);
694 op1 = TREE_OPERAND (t, 1);
695 while (TREE_CODE (op1) == INTEGER_CST)
696 {
697 tree dom = TYPE_DOMAIN (TREE_TYPE (op0));
698
699 /* Test for index in range. Break if not. */
700 if (!dom
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)))
707 break;
708
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))
712 return;
713
714 /* Only continue if we're still looking at an array. */
715 if (TREE_CODE (op0) != ARRAY_REF)
716 break;
717
718 op1 = TREE_OPERAND (op0, 1);
719 op0 = TREE_OPERAND (op0, 0);
720 }
721
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);
725 }
726 break;
727
728 case INDIRECT_REF:
729 addr = TREE_OPERAND (t, 0);
730 ptr_type = TREE_TYPE (addr);
731 break;
732
733 case ARRAY_RANGE_REF:
734 warning ("mudflap checking not yet implemented for ARRAY_RANGE_REF");
735 return;
736
737 case COMPONENT_REF:
738 {
739 tree field;
740
741 /* If we're not dereferencing something, then the access
742 must be ok. */
743 if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
744 return;
745
746 field = TREE_OPERAND (t, 1);
747
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))
752 {
753 if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST)
754 size = DECL_SIZE_UNIT (field);
755
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))));
761 }
762 else
763 {
764 ptr_type = build_pointer_type (type);
765 addr = build1 (ADDR_EXPR, ptr_type, t);
766 }
767 }
768 break;
769
770 case BIT_FIELD_REF:
771 {
772 tree ofs, rem, bpu;
773
774 /* If we're not dereferencing something, then the access
775 must be ok. */
776 if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF)
777 return;
778
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);
783
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);
788
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));
792 }
793 break;
794
795 default:
796 return;
797 }
798
799 mf_build_check_statement_for (addr, size, iter, locus, dirflag);
800 }
801
802 static void
803 mf_xform_derefs (void)
804 {
805 basic_block bb, next;
806 block_stmt_iterator i;
807 int saved_last_basic_block = last_basic_block;
808
809 bb = ENTRY_BLOCK_PTR ->next_bb;
810 do
811 {
812 next = bb->next_bb;
813 for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
814 {
815 tree s = bsi_stmt (i);
816
817 /* Only a few GIMPLE statements can reference memory. */
818 switch (TREE_CODE (s))
819 {
820 case MODIFY_EXPR:
821 mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
822 integer_one_node);
823 mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 1), EXPR_LOCUS (s),
824 integer_zero_node);
825 break;
826
827 case RETURN_EXPR:
828 if (TREE_OPERAND (s, 0) != NULL_TREE)
829 {
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);
833 else
834 mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s),
835 integer_zero_node);
836 }
837 break;
838
839 default:
840 ;
841 }
842 }
843 bb = next;
844 }
845 while (bb && bb->index <= saved_last_basic_block);
846 }
847
848 /* ------------------------------------------------------------------------ */
849 /* ADDR_EXPR transforms. Perform the declaration-related mudflap tree
850 transforms on the current function.
851
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. */
856
857 static void
858 execute_mudflap_function_decls (void)
859 {
860 if (mf_marked_p (current_function_decl))
861 return;
862
863 push_gimplify_context ();
864
865 mf_xform_decls (DECL_SAVED_TREE (current_function_decl),
866 DECL_ARGUMENTS (current_function_decl));
867
868 pop_gimplify_context (NULL);
869 }
870
871 /* This struct is passed between mf_xform_decls to store state needed
872 during the traversal searching for objects that have their
873 addresses taken. */
874 struct mf_xform_decls_data
875 {
876 tree param_decls;
877 };
878
879
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. */
883 static void
884 mx_register_decls (tree decl, tree *stmt_list)
885 {
886 tree finally_stmts = NULL_TREE;
887 tree_stmt_iterator initially_stmts = tsi_start (*stmt_list);
888
889 while (decl != NULL_TREE)
890 {
891 /* Eligible decl? */
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))
904 {
905 tree size = NULL_TREE, variable_name;
906 tree unregister_fncall, unregister_fncall_params;
907 tree register_fncall, register_fncall_params;
908
909 size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl)));
910
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)),
917 decl))),
918 tree_cons (NULL_TREE,
919 size,
920 tree_cons (NULL_TREE,
921 build_int_2 (3, 0), /* __MF_TYPE_STACK */
922 NULL_TREE)));
923 /* __mf_unregister (...) */
924 unregister_fncall = build_function_call_expr (mf_unregister_fndecl,
925 unregister_fncall_params);
926
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)),
934 decl))),
935 tree_cons (NULL_TREE,
936 size,
937 tree_cons (NULL_TREE,
938 build_int_2 (3, 0), /* __MF_TYPE_STACK */
939 tree_cons (NULL_TREE,
940 variable_name,
941 NULL_TREE))));
942
943 /* __mf_register (...) */
944 register_fncall = build_function_call_expr (mf_register_fndecl,
945 register_fncall_params);
946
947 /* Accumulate the two calls. */
948 /* ??? Set EXPR_LOCATION. */
949 gimplify_stmt (&register_fncall);
950 gimplify_stmt (&unregister_fncall);
951
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);
956
957 /* Accumulate the FINALLY piece. */
958 append_to_statement_list (unregister_fncall, &finally_stmts);
959
960 mf_mark (decl);
961 }
962
963 decl = TREE_CHAIN (decl);
964 }
965
966 /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */
967 if (finally_stmts != NULL_TREE)
968 {
969 tree t = build (TRY_FINALLY_EXPR, void_type_node,
970 *stmt_list, finally_stmts);
971 *stmt_list = NULL;
972 append_to_statement_list (t, stmt_list);
973 }
974 }
975
976
977 /* Process every variable mentioned in BIND_EXPRs. */
978 static tree
979 mx_xfn_xform_decls (tree *t, int *continue_p, void *data)
980 {
981 struct mf_xform_decls_data* d = (struct mf_xform_decls_data*) data;
982
983 if (*t == NULL_TREE || *t == error_mark_node)
984 {
985 *continue_p = 0;
986 return NULL_TREE;
987 }
988
989 *continue_p = 1;
990
991 switch (TREE_CODE (*t))
992 {
993 case BIND_EXPR:
994 {
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;
998
999 mx_register_decls (BIND_EXPR_VARS (*t), &BIND_EXPR_BODY (*t));
1000 }
1001 break;
1002
1003 default:
1004 break;
1005 }
1006
1007 return NULL;
1008 }
1009
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.
1012
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.
1016 */
1017
1018 static void
1019 mf_xform_decls (tree fnbody, tree fnparams)
1020 {
1021 struct mf_xform_decls_data d;
1022 d.param_decls = fnparams;
1023 walk_tree_without_duplicates (&fnbody, mx_xfn_xform_decls, &d);
1024 }
1025
1026
1027 /* ------------------------------------------------------------------------ */
1028 /* Externally visible mudflap functions. */
1029
1030
1031 /* Mark and return the given tree node to prevent further mudflap
1032 transforms. */
1033 static GTY ((param_is (union tree_node))) htab_t marked_trees = NULL;
1034
1035 tree
1036 mf_mark (tree t)
1037 {
1038 void **slot;
1039
1040 if (marked_trees == NULL)
1041 marked_trees = htab_create_ggc (31, htab_hash_pointer, htab_eq_pointer, NULL);
1042
1043 slot = htab_find_slot (marked_trees, t, INSERT);
1044 *slot = t;
1045 return t;
1046 }
1047
1048 int
1049 mf_marked_p (tree t)
1050 {
1051 void *entry;
1052
1053 if (marked_trees == NULL)
1054 return 0;
1055
1056 entry = htab_find (marked_trees, t);
1057 return (entry != NULL);
1058 }
1059
1060 /* Remember given node as a static of some kind: global data,
1061 function-scope static, or an anonymous constant. Its assembler
1062 label is given. */
1063
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. */
1068
1069 static GTY (()) varray_type deferred_static_decls;
1070
1071 /* A list of statements for calling __mf_register() at startup time. */
1072 static GTY (()) tree enqueued_call_stmt_chain;
1073
1074 static void
1075 mudflap_register_call (tree obj, tree object_size, tree varname)
1076 {
1077 tree arg, args, call_stmt;
1078
1079 args = tree_cons (NULL_TREE, varname, NULL_TREE);
1080
1081 arg = build_int_2 (4, 0); /* __MF_TYPE_STATIC */
1082 args = tree_cons (NULL_TREE, arg, args);
1083
1084 arg = convert (size_type_node, object_size);
1085 args = tree_cons (NULL_TREE, arg, args);
1086
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);
1090
1091 call_stmt = build_function_call_expr (mf_register_fndecl, args);
1092
1093 append_to_statement_list (call_stmt, &enqueued_call_stmt_chain);
1094 }
1095
1096 void
1097 mudflap_enqueue_decl (tree obj)
1098 {
1099 if (mf_marked_p (obj))
1100 return;
1101
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))
1108 return;
1109
1110 if (COMPLETE_TYPE_P (TREE_TYPE (obj)))
1111 {
1112 tree object_size;
1113
1114 mf_mark (obj);
1115
1116 object_size = size_in_bytes (TREE_TYPE (obj));
1117
1118 if (dump_file)
1119 {
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");
1125 }
1126
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. */
1131
1132 mudflap_register_call (obj, object_size, mf_varname_tree (obj));
1133 }
1134 else
1135 {
1136 size_t i;
1137
1138 if (! deferred_static_decls)
1139 VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list");
1140
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)
1144 {
1145 warning ("mudflap cannot track lifetime of `%s'",
1146 IDENTIFIER_POINTER (DECL_NAME (obj)));
1147 return;
1148 }
1149
1150 VARRAY_PUSH_TREE (deferred_static_decls, obj);
1151 }
1152 }
1153
1154 void
1155 mudflap_enqueue_constant (tree obj)
1156 {
1157 tree object_size, varname;
1158
1159 if (mf_marked_p (obj))
1160 return;
1161
1162 if (TREE_CODE (obj) == STRING_CST)
1163 object_size = build_int_2 (TREE_STRING_LENGTH (obj), 0);
1164 else
1165 object_size = size_in_bytes (TREE_TYPE (obj));
1166
1167 if (dump_file)
1168 {
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");
1174 }
1175
1176 if (TREE_CODE (obj) == STRING_CST)
1177 varname = mf_build_string ("string literal");
1178 else
1179 varname = mf_build_string ("constant");
1180
1181 mudflap_register_call (obj, object_size, varname);
1182 }
1183
1184
1185 /* Emit any file-wide instrumentation. */
1186 void
1187 mudflap_finish_file (void)
1188 {
1189 tree ctor_statements = NULL_TREE;
1190
1191 /* Try to give the deferred objects one final try. */
1192 if (deferred_static_decls)
1193 {
1194 size_t i;
1195
1196 for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++)
1197 {
1198 tree obj = VARRAY_TREE (deferred_static_decls, i);
1199
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);
1204 }
1205
1206 VARRAY_CLEAR (deferred_static_decls);
1207 }
1208
1209 /* Insert a call to __mf_init. */
1210 {
1211 tree call2_stmt = build_function_call_expr (mf_init_fndecl, NULL_TREE);
1212 append_to_statement_list (call2_stmt, &ctor_statements);
1213 }
1214
1215 /* If appropriate, call __mf_set_options to pass along read-ignore mode. */
1216 if (flag_mudflap_ignore_reads)
1217 {
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);
1222 }
1223
1224 /* Append all the enqueued registration calls. */
1225 if (enqueued_call_stmt_chain)
1226 {
1227 append_to_statement_list (enqueued_call_stmt_chain, &ctor_statements);
1228 enqueued_call_stmt_chain = NULL_TREE;
1229 }
1230
1231 cgraph_build_static_cdtor ('I', ctor_statements,
1232 MAX_RESERVED_INIT_PRIORITY-1);
1233 }
1234
1235
1236 static bool
1237 gate_mudflap (void)
1238 {
1239 return flag_mudflap != 0;
1240 }
1241
1242 struct tree_opt_pass pass_mudflap_1 =
1243 {
1244 "mudflap1", /* name */
1245 gate_mudflap, /* gate */
1246 execute_mudflap_function_decls, /* execute */
1247 NULL, /* sub */
1248 NULL, /* next */
1249 0, /* static_pass_number */
1250 0, /* tv_id */
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 */
1256 };
1257
1258 struct tree_opt_pass pass_mudflap_2 =
1259 {
1260 "mudflap2", /* name */
1261 gate_mudflap, /* gate */
1262 execute_mudflap_function_ops, /* execute */
1263 NULL, /* sub */
1264 NULL, /* next */
1265 0, /* static_pass_number */
1266 0, /* tv_id */
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 */
1273 };
1274
1275 #include "gt-tree-mudflap.h"
This page took 0.098711 seconds and 6 git commands to generate.