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