1169689Skan/* Mudflap: narrow-pointer bounds-checking by tree rewriting. 2169689Skan Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 3169689Skan Contributed by Frank Ch. Eigler <fche@redhat.com> 4169689Skan and Graydon Hoare <graydon@redhat.com> 5169689Skan 6169689SkanThis file is part of GCC. 7169689Skan 8169689SkanGCC is free software; you can redistribute it and/or modify it under 9169689Skanthe terms of the GNU General Public License as published by the Free 10169689SkanSoftware Foundation; either version 2, or (at your option) any later 11169689Skanversion. 12169689Skan 13169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 14169689SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 15169689SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16169689Skanfor more details. 17169689Skan 18169689SkanYou should have received a copy of the GNU General Public License 19169689Skanalong with GCC; see the file COPYING. If not, write to the Free 20169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 21169689Skan02110-1301, USA. */ 22169689Skan 23169689Skan 24169689Skan#include "config.h" 25169689Skan#include "system.h" 26169689Skan#include "coretypes.h" 27169689Skan#include "tm.h" 28169689Skan#include "hard-reg-set.h" 29169689Skan#include "rtl.h" 30169689Skan#include "tree.h" 31169689Skan#include "tm_p.h" 32169689Skan#include "basic-block.h" 33169689Skan#include "flags.h" 34169689Skan#include "function.h" 35169689Skan#include "tree-inline.h" 36169689Skan#include "tree-gimple.h" 37169689Skan#include "tree-flow.h" 38169689Skan#include "tree-mudflap.h" 39169689Skan#include "tree-dump.h" 40169689Skan#include "tree-pass.h" 41169689Skan#include "hashtab.h" 42169689Skan#include "diagnostic.h" 43169689Skan#include <demangle.h> 44169689Skan#include "langhooks.h" 45169689Skan#include "ggc.h" 46169689Skan#include "cgraph.h" 47169689Skan#include "toplev.h" 48169689Skan 49169689Skan/* Internal function decls */ 50169689Skan 51169689Skan 52169689Skan/* Options. */ 53169689Skan#define flag_mudflap_threads (flag_mudflap == 2) 54169689Skan 55169689Skan/* Helpers. */ 56169689Skanstatic tree mf_build_string (const char *string); 57169689Skanstatic tree mf_varname_tree (tree); 58169689Skanstatic tree mf_file_function_line_tree (location_t); 59169689Skan 60169689Skan/* Indirection-related instrumentation. */ 61169689Skanstatic void mf_decl_cache_locals (void); 62169689Skanstatic void mf_decl_clear_locals (void); 63169689Skanstatic void mf_xform_derefs (void); 64169689Skanstatic unsigned int execute_mudflap_function_ops (void); 65169689Skan 66169689Skan/* Addressable variables instrumentation. */ 67169689Skanstatic void mf_xform_decls (tree, tree); 68169689Skanstatic tree mx_xfn_xform_decls (tree *, int *, void *); 69169689Skanstatic void mx_register_decls (tree, tree *); 70169689Skanstatic unsigned int execute_mudflap_function_decls (void); 71169689Skan 72169689Skan 73169689Skan/* ------------------------------------------------------------------------ */ 74169689Skan/* Some generally helpful functions for mudflap instrumentation. */ 75169689Skan 76169689Skan/* Build a reference to a literal string. */ 77169689Skanstatic tree 78169689Skanmf_build_string (const char *string) 79169689Skan{ 80169689Skan size_t len = strlen (string); 81169689Skan tree result = mf_mark (build_string (len + 1, string)); 82169689Skan 83169689Skan TREE_TYPE (result) = build_array_type 84169689Skan (char_type_node, build_index_type (build_int_cst (NULL_TREE, len))); 85169689Skan TREE_CONSTANT (result) = 1; 86169689Skan TREE_INVARIANT (result) = 1; 87169689Skan TREE_READONLY (result) = 1; 88169689Skan TREE_STATIC (result) = 1; 89169689Skan 90169689Skan result = build1 (ADDR_EXPR, build_pointer_type (char_type_node), result); 91169689Skan 92169689Skan return mf_mark (result); 93169689Skan} 94169689Skan 95169689Skan/* Create a properly typed STRING_CST node that describes the given 96169689Skan declaration. It will be used as an argument for __mf_register(). 97169689Skan Try to construct a helpful string, including file/function/variable 98169689Skan name. */ 99169689Skan 100169689Skanstatic tree 101169689Skanmf_varname_tree (tree decl) 102169689Skan{ 103169689Skan static pretty_printer buf_rec; 104169689Skan static int initialized = 0; 105169689Skan pretty_printer *buf = & buf_rec; 106169689Skan const char *buf_contents; 107169689Skan tree result; 108169689Skan 109169689Skan gcc_assert (decl); 110169689Skan 111169689Skan if (!initialized) 112169689Skan { 113169689Skan pp_construct (buf, /* prefix */ NULL, /* line-width */ 0); 114169689Skan initialized = 1; 115169689Skan } 116169689Skan pp_clear_output_area (buf); 117169689Skan 118169689Skan /* Add FILENAME[:LINENUMBER[:COLUMNNUMBER]]. */ 119169689Skan { 120169689Skan expanded_location xloc = expand_location (DECL_SOURCE_LOCATION (decl)); 121169689Skan const char *sourcefile; 122169689Skan unsigned sourceline = xloc.line; 123169689Skan unsigned sourcecolumn = 0; 124169689Skan#ifdef USE_MAPPED_LOCATION 125169689Skan sourcecolumn = xloc.column; 126169689Skan#endif 127169689Skan sourcefile = xloc.file; 128169689Skan if (sourcefile == NULL && current_function_decl != NULL_TREE) 129169689Skan sourcefile = DECL_SOURCE_FILE (current_function_decl); 130169689Skan if (sourcefile == NULL) 131169689Skan sourcefile = "<unknown file>"; 132169689Skan 133169689Skan pp_string (buf, sourcefile); 134169689Skan 135169689Skan if (sourceline != 0) 136169689Skan { 137169689Skan pp_string (buf, ":"); 138169689Skan pp_decimal_int (buf, sourceline); 139169689Skan 140169689Skan if (sourcecolumn != 0) 141169689Skan { 142169689Skan pp_string (buf, ":"); 143169689Skan pp_decimal_int (buf, sourcecolumn); 144169689Skan } 145169689Skan } 146169689Skan } 147169689Skan 148169689Skan if (current_function_decl != NULL_TREE) 149169689Skan { 150169689Skan /* Add (FUNCTION) */ 151169689Skan pp_string (buf, " ("); 152169689Skan { 153169689Skan const char *funcname = NULL; 154169689Skan if (DECL_NAME (current_function_decl)) 155169689Skan funcname = lang_hooks.decl_printable_name (current_function_decl, 1); 156169689Skan if (funcname == NULL) 157169689Skan funcname = "anonymous fn"; 158169689Skan 159169689Skan pp_string (buf, funcname); 160169689Skan } 161169689Skan pp_string (buf, ") "); 162169689Skan } 163169689Skan else 164169689Skan pp_string (buf, " "); 165169689Skan 166169689Skan /* Add <variable-declaration>, possibly demangled. */ 167169689Skan { 168169689Skan const char *declname = NULL; 169169689Skan 170169689Skan if (DECL_NAME (decl) != NULL) 171169689Skan { 172169689Skan if (strcmp ("GNU C++", lang_hooks.name) == 0) 173169689Skan { 174169689Skan /* The gcc/cp decl_printable_name hook doesn't do as good a job as 175169689Skan the libiberty demangler. */ 176169689Skan declname = cplus_demangle (IDENTIFIER_POINTER (DECL_NAME (decl)), 177169689Skan DMGL_AUTO | DMGL_VERBOSE); 178169689Skan } 179169689Skan if (declname == NULL) 180169689Skan declname = lang_hooks.decl_printable_name (decl, 3); 181169689Skan } 182169689Skan if (declname == NULL) 183169689Skan declname = "<unnamed variable>"; 184169689Skan 185169689Skan pp_string (buf, declname); 186169689Skan } 187169689Skan 188169689Skan /* Return the lot as a new STRING_CST. */ 189169689Skan buf_contents = pp_base_formatted_text (buf); 190169689Skan result = mf_build_string (buf_contents); 191169689Skan pp_clear_output_area (buf); 192169689Skan 193169689Skan return result; 194169689Skan} 195169689Skan 196169689Skan 197169689Skan/* And another friend, for producing a simpler message. */ 198169689Skan 199169689Skanstatic tree 200169689Skanmf_file_function_line_tree (location_t location) 201169689Skan{ 202169689Skan expanded_location xloc = expand_location (location); 203169689Skan const char *file = NULL, *colon, *line, *op, *name, *cp; 204169689Skan char linecolbuf[30]; /* Enough for two decimal numbers plus a colon. */ 205169689Skan char *string; 206169689Skan tree result; 207169689Skan 208169689Skan /* Add FILENAME[:LINENUMBER[:COLUMNNUMBER]]. */ 209169689Skan file = xloc.file; 210169689Skan if (file == NULL && current_function_decl != NULL_TREE) 211169689Skan file = DECL_SOURCE_FILE (current_function_decl); 212169689Skan if (file == NULL) 213169689Skan file = "<unknown file>"; 214169689Skan 215169689Skan if (xloc.line > 0) 216169689Skan { 217169689Skan#ifdef USE_MAPPED_LOCATION 218169689Skan if (xloc.column > 0) 219169689Skan sprintf (linecolbuf, "%d:%d", xloc.line, xloc.column); 220169689Skan else 221169689Skan#endif 222169689Skan sprintf (linecolbuf, "%d", xloc.line); 223169689Skan colon = ":"; 224169689Skan line = linecolbuf; 225169689Skan } 226169689Skan else 227169689Skan colon = line = ""; 228169689Skan 229169689Skan /* Add (FUNCTION). */ 230169689Skan name = lang_hooks.decl_printable_name (current_function_decl, 1); 231169689Skan if (name) 232169689Skan { 233169689Skan op = " ("; 234169689Skan cp = ")"; 235169689Skan } 236169689Skan else 237169689Skan op = name = cp = ""; 238169689Skan 239169689Skan string = concat (file, colon, line, op, name, cp, NULL); 240169689Skan result = mf_build_string (string); 241169689Skan free (string); 242169689Skan 243169689Skan return result; 244169689Skan} 245169689Skan 246169689Skan 247169689Skan/* global tree nodes */ 248169689Skan 249169689Skan/* Global tree objects for global variables and functions exported by 250169689Skan mudflap runtime library. mf_init_extern_trees must be called 251169689Skan before using these. */ 252169689Skan 253169689Skan/* uintptr_t (usually "unsigned long") */ 254169689Skanstatic GTY (()) tree mf_uintptr_type; 255169689Skan 256169689Skan/* struct __mf_cache { uintptr_t low; uintptr_t high; }; */ 257169689Skanstatic GTY (()) tree mf_cache_struct_type; 258169689Skan 259169689Skan/* struct __mf_cache * const */ 260169689Skanstatic GTY (()) tree mf_cache_structptr_type; 261169689Skan 262169689Skan/* extern struct __mf_cache __mf_lookup_cache []; */ 263169689Skanstatic GTY (()) tree mf_cache_array_decl; 264169689Skan 265169689Skan/* extern unsigned char __mf_lc_shift; */ 266169689Skanstatic GTY (()) tree mf_cache_shift_decl; 267169689Skan 268169689Skan/* extern uintptr_t __mf_lc_mask; */ 269169689Skanstatic GTY (()) tree mf_cache_mask_decl; 270169689Skan 271169689Skan/* Their function-scope local shadows, used in single-threaded mode only. */ 272169689Skan 273169689Skan/* auto const unsigned char __mf_lc_shift_l; */ 274169689Skanstatic GTY (()) tree mf_cache_shift_decl_l; 275169689Skan 276169689Skan/* auto const uintptr_t __mf_lc_mask_l; */ 277169689Skanstatic GTY (()) tree mf_cache_mask_decl_l; 278169689Skan 279169689Skan/* extern void __mf_check (void *ptr, size_t sz, int type, const char *); */ 280169689Skanstatic GTY (()) tree mf_check_fndecl; 281169689Skan 282169689Skan/* extern void __mf_register (void *ptr, size_t sz, int type, const char *); */ 283169689Skanstatic GTY (()) tree mf_register_fndecl; 284169689Skan 285169689Skan/* extern void __mf_unregister (void *ptr, size_t sz, int type); */ 286169689Skanstatic GTY (()) tree mf_unregister_fndecl; 287169689Skan 288169689Skan/* extern void __mf_init (); */ 289169689Skanstatic GTY (()) tree mf_init_fndecl; 290169689Skan 291169689Skan/* extern int __mf_set_options (const char*); */ 292169689Skanstatic GTY (()) tree mf_set_options_fndecl; 293169689Skan 294169689Skan 295169689Skan/* Helper for mudflap_init: construct a decl with the given category, 296169689Skan name, and type, mark it an external reference, and pushdecl it. */ 297169689Skanstatic inline tree 298169689Skanmf_make_builtin (enum tree_code category, const char *name, tree type) 299169689Skan{ 300169689Skan tree decl = mf_mark (build_decl (category, get_identifier (name), type)); 301169689Skan TREE_PUBLIC (decl) = 1; 302169689Skan DECL_EXTERNAL (decl) = 1; 303169689Skan lang_hooks.decls.pushdecl (decl); 304169689Skan return decl; 305169689Skan} 306169689Skan 307169689Skan/* Helper for mudflap_init: construct a tree corresponding to the type 308169689Skan struct __mf_cache { uintptr_t low; uintptr_t high; }; 309169689Skan where uintptr_t is the FIELD_TYPE argument. */ 310169689Skanstatic inline tree 311169689Skanmf_make_mf_cache_struct_type (tree field_type) 312169689Skan{ 313169689Skan /* There is, abominably, no language-independent way to construct a 314169689Skan RECORD_TYPE. So we have to call the basic type construction 315169689Skan primitives by hand. */ 316169689Skan tree fieldlo = build_decl (FIELD_DECL, get_identifier ("low"), field_type); 317169689Skan tree fieldhi = build_decl (FIELD_DECL, get_identifier ("high"), field_type); 318169689Skan 319169689Skan tree struct_type = make_node (RECORD_TYPE); 320169689Skan DECL_CONTEXT (fieldlo) = struct_type; 321169689Skan DECL_CONTEXT (fieldhi) = struct_type; 322169689Skan TREE_CHAIN (fieldlo) = fieldhi; 323169689Skan TYPE_FIELDS (struct_type) = fieldlo; 324169689Skan TYPE_NAME (struct_type) = get_identifier ("__mf_cache"); 325169689Skan layout_type (struct_type); 326169689Skan 327169689Skan return struct_type; 328169689Skan} 329169689Skan 330169689Skan#define build_function_type_0(rtype) \ 331169689Skan build_function_type (rtype, void_list_node) 332169689Skan#define build_function_type_1(rtype, arg1) \ 333169689Skan build_function_type (rtype, tree_cons (0, arg1, void_list_node)) 334169689Skan#define build_function_type_3(rtype, arg1, arg2, arg3) \ 335169689Skan build_function_type (rtype, tree_cons (0, arg1, tree_cons (0, arg2, \ 336169689Skan tree_cons (0, arg3, void_list_node)))) 337169689Skan#define build_function_type_4(rtype, arg1, arg2, arg3, arg4) \ 338169689Skan build_function_type (rtype, tree_cons (0, arg1, tree_cons (0, arg2, \ 339169689Skan tree_cons (0, arg3, tree_cons (0, arg4, \ 340169689Skan void_list_node))))) 341169689Skan 342169689Skan/* Initialize the global tree nodes that correspond to mf-runtime.h 343169689Skan declarations. */ 344169689Skanvoid 345169689Skanmudflap_init (void) 346169689Skan{ 347169689Skan static bool done = false; 348169689Skan tree mf_const_string_type; 349169689Skan tree mf_cache_array_type; 350169689Skan tree mf_check_register_fntype; 351169689Skan tree mf_unregister_fntype; 352169689Skan tree mf_init_fntype; 353169689Skan tree mf_set_options_fntype; 354169689Skan 355169689Skan if (done) 356169689Skan return; 357169689Skan done = true; 358169689Skan 359169689Skan mf_uintptr_type = lang_hooks.types.type_for_mode (ptr_mode, 360169689Skan /*unsignedp=*/true); 361169689Skan mf_const_string_type 362169689Skan = build_pointer_type (build_qualified_type 363169689Skan (char_type_node, TYPE_QUAL_CONST)); 364169689Skan 365169689Skan mf_cache_struct_type = mf_make_mf_cache_struct_type (mf_uintptr_type); 366169689Skan mf_cache_structptr_type = build_pointer_type (mf_cache_struct_type); 367169689Skan mf_cache_array_type = build_array_type (mf_cache_struct_type, 0); 368169689Skan mf_check_register_fntype = 369169689Skan build_function_type_4 (void_type_node, ptr_type_node, size_type_node, 370169689Skan integer_type_node, mf_const_string_type); 371169689Skan mf_unregister_fntype = 372169689Skan build_function_type_3 (void_type_node, ptr_type_node, size_type_node, 373169689Skan integer_type_node); 374169689Skan mf_init_fntype = 375169689Skan build_function_type_0 (void_type_node); 376169689Skan mf_set_options_fntype = 377169689Skan build_function_type_1 (integer_type_node, mf_const_string_type); 378169689Skan 379169689Skan mf_cache_array_decl = mf_make_builtin (VAR_DECL, "__mf_lookup_cache", 380169689Skan mf_cache_array_type); 381169689Skan mf_cache_shift_decl = mf_make_builtin (VAR_DECL, "__mf_lc_shift", 382169689Skan unsigned_char_type_node); 383169689Skan mf_cache_mask_decl = mf_make_builtin (VAR_DECL, "__mf_lc_mask", 384169689Skan mf_uintptr_type); 385169689Skan /* Don't process these in mudflap_enqueue_decl, should they come by 386169689Skan there for some reason. */ 387169689Skan mf_mark (mf_cache_array_decl); 388169689Skan mf_mark (mf_cache_shift_decl); 389169689Skan mf_mark (mf_cache_mask_decl); 390169689Skan mf_check_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_check", 391169689Skan mf_check_register_fntype); 392169689Skan mf_register_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_register", 393169689Skan mf_check_register_fntype); 394169689Skan mf_unregister_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_unregister", 395169689Skan mf_unregister_fntype); 396169689Skan mf_init_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_init", 397169689Skan mf_init_fntype); 398169689Skan mf_set_options_fndecl = mf_make_builtin (FUNCTION_DECL, "__mf_set_options", 399169689Skan mf_set_options_fntype); 400169689Skan} 401169689Skan#undef build_function_type_4 402169689Skan#undef build_function_type_3 403169689Skan#undef build_function_type_1 404169689Skan#undef build_function_type_0 405169689Skan 406169689Skan 407169689Skan/* ------------------------------------------------------------------------ */ 408169689Skan/* Memory reference transforms. Perform the mudflap indirection-related 409169689Skan tree transforms on the current function. 410169689Skan 411169689Skan This is the second part of the mudflap instrumentation. It works on 412169689Skan low-level GIMPLE using the CFG, because we want to run this pass after 413169689Skan tree optimizations have been performed, but we have to preserve the CFG 414169689Skan for expansion from trees to RTL. */ 415169689Skan 416169689Skanstatic unsigned int 417169689Skanexecute_mudflap_function_ops (void) 418169689Skan{ 419169689Skan /* Don't instrument functions such as the synthetic constructor 420169689Skan built during mudflap_finish_file. */ 421169689Skan if (mf_marked_p (current_function_decl) || 422169689Skan DECL_ARTIFICIAL (current_function_decl)) 423169689Skan return 0; 424169689Skan 425169689Skan push_gimplify_context (); 426169689Skan 427169689Skan /* In multithreaded mode, don't cache the lookup cache parameters. */ 428169689Skan if (! flag_mudflap_threads) 429169689Skan mf_decl_cache_locals (); 430169689Skan 431169689Skan mf_xform_derefs (); 432169689Skan 433169689Skan if (! flag_mudflap_threads) 434169689Skan mf_decl_clear_locals (); 435169689Skan 436169689Skan pop_gimplify_context (NULL); 437169689Skan return 0; 438169689Skan} 439169689Skan 440169689Skan/* Create and initialize local shadow variables for the lookup cache 441169689Skan globals. Put their decls in the *_l globals for use by 442169689Skan mf_build_check_statement_for. */ 443169689Skan 444169689Skanstatic void 445169689Skanmf_decl_cache_locals (void) 446169689Skan{ 447169689Skan tree t, shift_init_stmts, mask_init_stmts; 448169689Skan tree_stmt_iterator tsi; 449169689Skan 450169689Skan /* Build the cache vars. */ 451169689Skan mf_cache_shift_decl_l 452169689Skan = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_shift_decl), 453169689Skan "__mf_lookup_shift_l")); 454169689Skan 455169689Skan mf_cache_mask_decl_l 456169689Skan = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_mask_decl), 457169689Skan "__mf_lookup_mask_l")); 458169689Skan 459169689Skan /* Build initialization nodes for the cache vars. We just load the 460169689Skan globals into the cache variables. */ 461169689Skan t = build2 (MODIFY_EXPR, TREE_TYPE (mf_cache_shift_decl_l), 462169689Skan mf_cache_shift_decl_l, mf_cache_shift_decl); 463169689Skan SET_EXPR_LOCATION (t, DECL_SOURCE_LOCATION (current_function_decl)); 464169689Skan gimplify_to_stmt_list (&t); 465169689Skan shift_init_stmts = t; 466169689Skan 467169689Skan t = build2 (MODIFY_EXPR, TREE_TYPE (mf_cache_mask_decl_l), 468169689Skan mf_cache_mask_decl_l, mf_cache_mask_decl); 469169689Skan SET_EXPR_LOCATION (t, DECL_SOURCE_LOCATION (current_function_decl)); 470169689Skan gimplify_to_stmt_list (&t); 471169689Skan mask_init_stmts = t; 472169689Skan 473169689Skan /* Anticipating multiple entry points, we insert the cache vars 474169689Skan initializers in each successor of the ENTRY_BLOCK_PTR. */ 475169689Skan for (tsi = tsi_start (shift_init_stmts); 476169689Skan ! tsi_end_p (tsi); 477169689Skan tsi_next (&tsi)) 478169689Skan insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR); 479169689Skan 480169689Skan for (tsi = tsi_start (mask_init_stmts); 481169689Skan ! tsi_end_p (tsi); 482169689Skan tsi_next (&tsi)) 483169689Skan insert_edge_copies (tsi_stmt (tsi), ENTRY_BLOCK_PTR); 484169689Skan bsi_commit_edge_inserts (); 485169689Skan} 486169689Skan 487169689Skan 488169689Skanstatic void 489169689Skanmf_decl_clear_locals (void) 490169689Skan{ 491169689Skan /* Unset local shadows. */ 492169689Skan mf_cache_shift_decl_l = NULL_TREE; 493169689Skan mf_cache_mask_decl_l = NULL_TREE; 494169689Skan} 495169689Skan 496169689Skanstatic void 497169689Skanmf_build_check_statement_for (tree base, tree limit, 498169689Skan block_stmt_iterator *instr_bsi, 499169689Skan location_t *locus, tree dirflag) 500169689Skan{ 501169689Skan tree_stmt_iterator head, tsi; 502169689Skan block_stmt_iterator bsi; 503169689Skan basic_block cond_bb, then_bb, join_bb; 504169689Skan edge e; 505169689Skan tree cond, t, u, v; 506169689Skan tree mf_base; 507169689Skan tree mf_elem; 508169689Skan tree mf_limit; 509169689Skan 510169689Skan /* We first need to split the current basic block, and start altering 511169689Skan the CFG. This allows us to insert the statements we're about to 512169689Skan construct into the right basic blocks. */ 513169689Skan 514169689Skan cond_bb = bb_for_stmt (bsi_stmt (*instr_bsi)); 515169689Skan bsi = *instr_bsi; 516169689Skan bsi_prev (&bsi); 517169689Skan if (! bsi_end_p (bsi)) 518169689Skan e = split_block (cond_bb, bsi_stmt (bsi)); 519169689Skan else 520169689Skan e = split_block_after_labels (cond_bb); 521169689Skan cond_bb = e->src; 522169689Skan join_bb = e->dest; 523169689Skan 524169689Skan /* A recap at this point: join_bb is the basic block at whose head 525169689Skan is the gimple statement for which this check expression is being 526169689Skan built. cond_bb is the (possibly new, synthetic) basic block the 527169689Skan end of which will contain the cache-lookup code, and a 528169689Skan conditional that jumps to the cache-miss code or, much more 529169689Skan likely, over to join_bb. */ 530169689Skan 531169689Skan /* Create the bb that contains the cache-miss fallback block (mf_check). */ 532169689Skan then_bb = create_empty_bb (cond_bb); 533169689Skan make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE); 534169689Skan make_single_succ_edge (then_bb, join_bb, EDGE_FALLTHRU); 535169689Skan 536169689Skan /* Mark the pseudo-fallthrough edge from cond_bb to join_bb. */ 537169689Skan e = find_edge (cond_bb, join_bb); 538169689Skan e->flags = EDGE_FALSE_VALUE; 539169689Skan e->count = cond_bb->count; 540169689Skan e->probability = REG_BR_PROB_BASE; 541169689Skan 542169689Skan /* Update dominance info. Note that bb_join's data was 543169689Skan updated by split_block. */ 544169689Skan if (dom_info_available_p (CDI_DOMINATORS)) 545169689Skan { 546169689Skan set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb); 547169689Skan set_immediate_dominator (CDI_DOMINATORS, join_bb, cond_bb); 548169689Skan } 549169689Skan 550169689Skan /* Build our local variables. */ 551169689Skan mf_elem = create_tmp_var (mf_cache_structptr_type, "__mf_elem"); 552169689Skan mf_base = create_tmp_var (mf_uintptr_type, "__mf_base"); 553169689Skan mf_limit = create_tmp_var (mf_uintptr_type, "__mf_limit"); 554169689Skan 555169689Skan /* Build: __mf_base = (uintptr_t) <base address expression>. */ 556169689Skan t = build2 (MODIFY_EXPR, void_type_node, mf_base, 557169689Skan convert (mf_uintptr_type, unshare_expr (base))); 558169689Skan SET_EXPR_LOCUS (t, locus); 559169689Skan gimplify_to_stmt_list (&t); 560169689Skan head = tsi_start (t); 561169689Skan tsi = tsi_last (t); 562169689Skan 563169689Skan /* Build: __mf_limit = (uintptr_t) <limit address expression>. */ 564169689Skan t = build2 (MODIFY_EXPR, void_type_node, mf_limit, 565169689Skan convert (mf_uintptr_type, unshare_expr (limit))); 566169689Skan SET_EXPR_LOCUS (t, locus); 567169689Skan gimplify_to_stmt_list (&t); 568169689Skan tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING); 569169689Skan 570169689Skan /* Build: __mf_elem = &__mf_lookup_cache [(__mf_base >> __mf_shift) 571169689Skan & __mf_mask]. */ 572169689Skan t = build2 (RSHIFT_EXPR, mf_uintptr_type, mf_base, 573169689Skan (flag_mudflap_threads ? mf_cache_shift_decl : mf_cache_shift_decl_l)); 574169689Skan t = build2 (BIT_AND_EXPR, mf_uintptr_type, t, 575169689Skan (flag_mudflap_threads ? mf_cache_mask_decl : mf_cache_mask_decl_l)); 576169689Skan t = build4 (ARRAY_REF, 577169689Skan TREE_TYPE (TREE_TYPE (mf_cache_array_decl)), 578169689Skan mf_cache_array_decl, t, NULL_TREE, NULL_TREE); 579169689Skan t = build1 (ADDR_EXPR, mf_cache_structptr_type, t); 580169689Skan t = build2 (MODIFY_EXPR, void_type_node, mf_elem, t); 581169689Skan SET_EXPR_LOCUS (t, locus); 582169689Skan gimplify_to_stmt_list (&t); 583169689Skan tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING); 584169689Skan 585169689Skan /* Quick validity check. 586169689Skan 587169689Skan if (__mf_elem->low > __mf_base 588169689Skan || (__mf_elem_high < __mf_limit)) 589169689Skan { 590169689Skan __mf_check (); 591169689Skan ... and only if single-threaded: 592169689Skan __mf_lookup_shift_1 = f...; 593169689Skan __mf_lookup_mask_l = ...; 594169689Skan } 595169689Skan 596169689Skan It is expected that this body of code is rarely executed so we mark 597169689Skan the edge to the THEN clause of the conditional jump as unlikely. */ 598169689Skan 599169689Skan /* Construct t <-- '__mf_elem->low > __mf_base'. */ 600169689Skan t = build3 (COMPONENT_REF, mf_uintptr_type, 601169689Skan build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem), 602169689Skan TYPE_FIELDS (mf_cache_struct_type), NULL_TREE); 603169689Skan t = build2 (GT_EXPR, boolean_type_node, t, mf_base); 604169689Skan 605169689Skan /* Construct '__mf_elem->high < __mf_limit'. 606169689Skan 607169689Skan First build: 608169689Skan 1) u <-- '__mf_elem->high' 609169689Skan 2) v <-- '__mf_limit'. 610169689Skan 611169689Skan Then build 'u <-- (u < v). */ 612169689Skan 613169689Skan u = build3 (COMPONENT_REF, mf_uintptr_type, 614169689Skan build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem), 615169689Skan TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type)), NULL_TREE); 616169689Skan 617169689Skan v = mf_limit; 618169689Skan 619169689Skan u = build2 (LT_EXPR, boolean_type_node, u, v); 620169689Skan 621169689Skan /* Build the composed conditional: t <-- 't || u'. Then store the 622169689Skan result of the evaluation of 't' in a temporary variable which we 623169689Skan can use as the condition for the conditional jump. */ 624169689Skan t = build2 (TRUTH_OR_EXPR, boolean_type_node, t, u); 625169689Skan cond = create_tmp_var (boolean_type_node, "__mf_unlikely_cond"); 626169689Skan t = build2 (MODIFY_EXPR, boolean_type_node, cond, t); 627169689Skan gimplify_to_stmt_list (&t); 628169689Skan tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING); 629169689Skan 630169689Skan /* Build the conditional jump. 'cond' is just a temporary so we can 631169689Skan simply build a void COND_EXPR. We do need labels in both arms though. */ 632169689Skan t = build3 (COND_EXPR, void_type_node, cond, 633169689Skan build1 (GOTO_EXPR, void_type_node, tree_block_label (then_bb)), 634169689Skan build1 (GOTO_EXPR, void_type_node, tree_block_label (join_bb))); 635169689Skan SET_EXPR_LOCUS (t, locus); 636169689Skan tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING); 637169689Skan 638169689Skan /* At this point, after so much hard work, we have only constructed 639169689Skan the conditional jump, 640169689Skan 641169689Skan if (__mf_elem->low > __mf_base 642169689Skan || (__mf_elem_high < __mf_limit)) 643169689Skan 644169689Skan The lowered GIMPLE tree representing this code is in the statement 645169689Skan list starting at 'head'. 646169689Skan 647169689Skan We can insert this now in the current basic block, i.e. the one that 648169689Skan the statement we're instrumenting was originally in. */ 649169689Skan bsi = bsi_last (cond_bb); 650169689Skan for (tsi = head; ! tsi_end_p (tsi); tsi_next (&tsi)) 651169689Skan bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_CONTINUE_LINKING); 652169689Skan 653169689Skan /* Now build up the body of the cache-miss handling: 654169689Skan 655169689Skan __mf_check(); 656169689Skan refresh *_l vars. 657169689Skan 658169689Skan This is the body of the conditional. */ 659169689Skan 660169689Skan u = tree_cons (NULL_TREE, 661169689Skan mf_file_function_line_tree (locus == NULL ? UNKNOWN_LOCATION 662169689Skan : *locus), 663169689Skan NULL_TREE); 664169689Skan u = tree_cons (NULL_TREE, dirflag, u); 665169689Skan /* NB: we pass the overall [base..limit] range to mf_check. */ 666169689Skan u = tree_cons (NULL_TREE, 667169689Skan fold_build2 (PLUS_EXPR, integer_type_node, 668169689Skan fold_build2 (MINUS_EXPR, mf_uintptr_type, mf_limit, mf_base), 669169689Skan integer_one_node), 670169689Skan u); 671169689Skan u = tree_cons (NULL_TREE, mf_base, u); 672169689Skan t = build_function_call_expr (mf_check_fndecl, u); 673169689Skan gimplify_to_stmt_list (&t); 674169689Skan head = tsi_start (t); 675169689Skan tsi = tsi_last (t); 676169689Skan 677169689Skan if (! flag_mudflap_threads) 678169689Skan { 679169689Skan t = build2 (MODIFY_EXPR, void_type_node, 680169689Skan mf_cache_shift_decl_l, mf_cache_shift_decl); 681169689Skan tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING); 682169689Skan 683169689Skan t = build2 (MODIFY_EXPR, void_type_node, 684169689Skan mf_cache_mask_decl_l, mf_cache_mask_decl); 685169689Skan tsi_link_after (&tsi, t, TSI_CONTINUE_LINKING); 686169689Skan } 687169689Skan 688169689Skan /* Insert the check code in the THEN block. */ 689169689Skan bsi = bsi_start (then_bb); 690169689Skan for (tsi = head; ! tsi_end_p (tsi); tsi_next (&tsi)) 691169689Skan bsi_insert_after (&bsi, tsi_stmt (tsi), BSI_CONTINUE_LINKING); 692169689Skan 693169689Skan *instr_bsi = bsi_start (join_bb); 694169689Skan bsi_next (instr_bsi); 695169689Skan} 696169689Skan 697169689Skan 698169689Skan/* Check whether the given decl, generally a VAR_DECL or PARM_DECL, is 699169689Skan eligible for instrumentation. For the mudflap1 pass, this implies 700169689Skan that it should be registered with the libmudflap runtime. For the 701169689Skan mudflap2 pass this means instrumenting an indirection operation with 702169689Skan respect to the object. 703169689Skan*/ 704169689Skanstatic int 705169689Skanmf_decl_eligible_p (tree decl) 706169689Skan{ 707169689Skan return ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) 708169689Skan /* The decl must have its address taken. In the case of 709169689Skan arrays, this flag is also set if the indexes are not 710169689Skan compile-time known valid constants. */ 711169689Skan && TREE_ADDRESSABLE (decl) /* XXX: not sufficient: return-by-value structs! */ 712169689Skan /* The type of the variable must be complete. */ 713169689Skan && COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl)) 714169689Skan /* The decl hasn't been decomposed somehow. */ 715169689Skan && !DECL_HAS_VALUE_EXPR_P (decl)); 716169689Skan} 717169689Skan 718169689Skan 719169689Skanstatic void 720169689Skanmf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp, 721169689Skan location_t *locus, tree dirflag) 722169689Skan{ 723169689Skan tree type, base, limit, addr, size, t; 724169689Skan 725169689Skan /* Don't instrument read operations. */ 726169689Skan if (dirflag == integer_zero_node && flag_mudflap_ignore_reads) 727169689Skan return; 728169689Skan 729169689Skan /* Don't instrument marked nodes. */ 730169689Skan if (mf_marked_p (*tp)) 731169689Skan return; 732169689Skan 733169689Skan t = *tp; 734169689Skan type = TREE_TYPE (t); 735169689Skan 736169689Skan if (type == error_mark_node) 737169689Skan return; 738169689Skan 739169689Skan size = TYPE_SIZE_UNIT (type); 740169689Skan 741169689Skan switch (TREE_CODE (t)) 742169689Skan { 743169689Skan case ARRAY_REF: 744169689Skan case COMPONENT_REF: 745169689Skan { 746169689Skan /* This is trickier than it may first appear. The reason is 747169689Skan that we are looking at expressions from the "inside out" at 748169689Skan this point. We may have a complex nested aggregate/array 749169689Skan expression (e.g. "a.b[i].c"), maybe with an indirection as 750169689Skan the leftmost operator ("p->a.b.d"), where instrumentation 751169689Skan is necessary. Or we may have an innocent "a.b.c" 752169689Skan expression that must not be instrumented. We need to 753169689Skan recurse all the way down the nesting structure to figure it 754169689Skan out: looking just at the outer node is not enough. */ 755169689Skan tree var; 756169689Skan int component_ref_only = (TREE_CODE (t) == COMPONENT_REF); 757169689Skan /* If we have a bitfield component reference, we must note the 758169689Skan innermost addressable object in ELT, from which we will 759169689Skan construct the byte-addressable bounds of the bitfield. */ 760169689Skan tree elt = NULL_TREE; 761169689Skan int bitfield_ref_p = (TREE_CODE (t) == COMPONENT_REF 762169689Skan && DECL_BIT_FIELD_TYPE (TREE_OPERAND (t, 1))); 763169689Skan 764169689Skan /* Iterate to the top of the ARRAY_REF/COMPONENT_REF 765169689Skan containment hierarchy to find the outermost VAR_DECL. */ 766169689Skan var = TREE_OPERAND (t, 0); 767169689Skan while (1) 768169689Skan { 769169689Skan if (bitfield_ref_p && elt == NULL_TREE 770169689Skan && (TREE_CODE (var) == ARRAY_REF || TREE_CODE (var) == COMPONENT_REF)) 771169689Skan elt = var; 772169689Skan 773169689Skan if (TREE_CODE (var) == ARRAY_REF) 774169689Skan { 775169689Skan component_ref_only = 0; 776169689Skan var = TREE_OPERAND (var, 0); 777169689Skan } 778169689Skan else if (TREE_CODE (var) == COMPONENT_REF) 779169689Skan var = TREE_OPERAND (var, 0); 780169689Skan else if (INDIRECT_REF_P (var)) 781169689Skan { 782169689Skan base = TREE_OPERAND (var, 0); 783169689Skan break; 784169689Skan } 785169689Skan else 786169689Skan { 787169689Skan gcc_assert (TREE_CODE (var) == VAR_DECL 788169689Skan || TREE_CODE (var) == PARM_DECL 789169689Skan || TREE_CODE (var) == RESULT_DECL 790169689Skan || TREE_CODE (var) == STRING_CST); 791169689Skan /* Don't instrument this access if the underlying 792169689Skan variable is not "eligible". This test matches 793169689Skan those arrays that have only known-valid indexes, 794169689Skan and thus are not labeled TREE_ADDRESSABLE. */ 795169689Skan if (! mf_decl_eligible_p (var) || component_ref_only) 796169689Skan return; 797169689Skan else 798169689Skan { 799169689Skan base = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (var)), var); 800169689Skan break; 801169689Skan } 802169689Skan } 803169689Skan } 804169689Skan 805169689Skan /* Handle the case of ordinary non-indirection structure 806169689Skan accesses. These have only nested COMPONENT_REF nodes (no 807169689Skan INDIRECT_REF), but pass through the above filter loop. 808169689Skan Note that it's possible for such a struct variable to match 809169689Skan the eligible_p test because someone else might take its 810169689Skan address sometime. */ 811169689Skan 812169689Skan /* We need special processing for bitfield components, because 813169689Skan their addresses cannot be taken. */ 814169689Skan if (bitfield_ref_p) 815169689Skan { 816169689Skan tree field = TREE_OPERAND (t, 1); 817169689Skan 818169689Skan if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST) 819169689Skan size = DECL_SIZE_UNIT (field); 820169689Skan 821169689Skan if (elt) 822169689Skan elt = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (elt)), elt); 823169689Skan addr = fold_convert (ptr_type_node, elt ? elt : base); 824169689Skan addr = fold_build2 (PLUS_EXPR, ptr_type_node, 825169689Skan addr, fold_convert (ptr_type_node, 826169689Skan byte_position (field))); 827169689Skan } 828169689Skan else 829169689Skan addr = build1 (ADDR_EXPR, build_pointer_type (type), t); 830169689Skan 831169689Skan limit = fold_build2 (MINUS_EXPR, mf_uintptr_type, 832169689Skan fold_build2 (PLUS_EXPR, mf_uintptr_type, 833169689Skan convert (mf_uintptr_type, addr), 834169689Skan size), 835169689Skan integer_one_node); 836169689Skan } 837169689Skan break; 838169689Skan 839169689Skan case INDIRECT_REF: 840169689Skan addr = TREE_OPERAND (t, 0); 841169689Skan base = addr; 842169689Skan limit = fold_build2 (MINUS_EXPR, ptr_type_node, 843169689Skan fold_build2 (PLUS_EXPR, ptr_type_node, base, size), 844169689Skan integer_one_node); 845169689Skan break; 846169689Skan 847169689Skan case TARGET_MEM_REF: 848169689Skan addr = tree_mem_ref_addr (ptr_type_node, t); 849169689Skan base = addr; 850169689Skan limit = fold_build2 (MINUS_EXPR, ptr_type_node, 851169689Skan fold_build2 (PLUS_EXPR, ptr_type_node, base, size), 852169689Skan build_int_cst (ptr_type_node, 1)); 853169689Skan break; 854169689Skan 855169689Skan case ARRAY_RANGE_REF: 856169689Skan warning (0, "mudflap checking not yet implemented for ARRAY_RANGE_REF"); 857169689Skan return; 858169689Skan 859169689Skan case BIT_FIELD_REF: 860169689Skan /* ??? merge with COMPONENT_REF code above? */ 861169689Skan { 862169689Skan tree ofs, rem, bpu; 863169689Skan 864169689Skan /* If we're not dereferencing something, then the access 865169689Skan must be ok. */ 866169689Skan if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF) 867169689Skan return; 868169689Skan 869169689Skan bpu = bitsize_int (BITS_PER_UNIT); 870169689Skan ofs = convert (bitsizetype, TREE_OPERAND (t, 2)); 871169689Skan rem = size_binop (TRUNC_MOD_EXPR, ofs, bpu); 872169689Skan ofs = size_binop (TRUNC_DIV_EXPR, ofs, bpu); 873169689Skan 874169689Skan size = convert (bitsizetype, TREE_OPERAND (t, 1)); 875169689Skan size = size_binop (PLUS_EXPR, size, rem); 876169689Skan size = size_binop (CEIL_DIV_EXPR, size, bpu); 877169689Skan size = convert (sizetype, size); 878169689Skan 879169689Skan addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0); 880169689Skan addr = convert (ptr_type_node, addr); 881169689Skan addr = fold_build2 (PLUS_EXPR, ptr_type_node, addr, ofs); 882169689Skan 883169689Skan base = addr; 884169689Skan limit = fold_build2 (MINUS_EXPR, ptr_type_node, 885169689Skan fold_build2 (PLUS_EXPR, ptr_type_node, base, size), 886169689Skan integer_one_node); 887169689Skan } 888169689Skan break; 889169689Skan 890169689Skan default: 891169689Skan return; 892169689Skan } 893169689Skan 894169689Skan mf_build_check_statement_for (base, limit, iter, locus, dirflag); 895169689Skan} 896169689Skan 897169689Skanstatic void 898169689Skanmf_xform_derefs (void) 899169689Skan{ 900169689Skan basic_block bb, next; 901169689Skan block_stmt_iterator i; 902169689Skan int saved_last_basic_block = last_basic_block; 903169689Skan 904169689Skan bb = ENTRY_BLOCK_PTR ->next_bb; 905169689Skan do 906169689Skan { 907169689Skan next = bb->next_bb; 908169689Skan for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i)) 909169689Skan { 910169689Skan tree s = bsi_stmt (i); 911169689Skan 912169689Skan /* Only a few GIMPLE statements can reference memory. */ 913169689Skan switch (TREE_CODE (s)) 914169689Skan { 915169689Skan case MODIFY_EXPR: 916169689Skan mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s), 917169689Skan integer_one_node); 918169689Skan mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 1), EXPR_LOCUS (s), 919169689Skan integer_zero_node); 920169689Skan break; 921169689Skan 922169689Skan case RETURN_EXPR: 923169689Skan if (TREE_OPERAND (s, 0) != NULL_TREE) 924169689Skan { 925169689Skan if (TREE_CODE (TREE_OPERAND (s, 0)) == MODIFY_EXPR) 926169689Skan mf_xform_derefs_1 (&i, &TREE_OPERAND (TREE_OPERAND (s, 0), 1), 927169689Skan EXPR_LOCUS (s), integer_zero_node); 928169689Skan else 929169689Skan mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s), 930169689Skan integer_zero_node); 931169689Skan } 932169689Skan break; 933169689Skan 934169689Skan default: 935169689Skan ; 936169689Skan } 937169689Skan } 938169689Skan bb = next; 939169689Skan } 940169689Skan while (bb && bb->index <= saved_last_basic_block); 941169689Skan} 942169689Skan 943169689Skan/* ------------------------------------------------------------------------ */ 944169689Skan/* ADDR_EXPR transforms. Perform the declaration-related mudflap tree 945169689Skan transforms on the current function. 946169689Skan 947169689Skan This is the first part of the mudflap instrumentation. It works on 948169689Skan high-level GIMPLE because after lowering, all variables are moved out 949169689Skan of their BIND_EXPR binding context, and we lose liveness information 950169689Skan for the declarations we wish to instrument. */ 951169689Skan 952169689Skanstatic unsigned int 953169689Skanexecute_mudflap_function_decls (void) 954169689Skan{ 955169689Skan /* Don't instrument functions such as the synthetic constructor 956169689Skan built during mudflap_finish_file. */ 957169689Skan if (mf_marked_p (current_function_decl) || 958169689Skan DECL_ARTIFICIAL (current_function_decl)) 959169689Skan return 0; 960169689Skan 961169689Skan push_gimplify_context (); 962169689Skan 963169689Skan mf_xform_decls (DECL_SAVED_TREE (current_function_decl), 964169689Skan DECL_ARGUMENTS (current_function_decl)); 965169689Skan 966169689Skan pop_gimplify_context (NULL); 967169689Skan return 0; 968169689Skan} 969169689Skan 970169689Skan/* This struct is passed between mf_xform_decls to store state needed 971169689Skan during the traversal searching for objects that have their 972169689Skan addresses taken. */ 973169689Skanstruct mf_xform_decls_data 974169689Skan{ 975169689Skan tree param_decls; 976169689Skan}; 977169689Skan 978169689Skan 979169689Skan/* Synthesize a CALL_EXPR and a TRY_FINALLY_EXPR, for this chain of 980169689Skan _DECLs if appropriate. Arrange to call the __mf_register function 981169689Skan now, and the __mf_unregister function later for each. */ 982169689Skanstatic void 983169689Skanmx_register_decls (tree decl, tree *stmt_list) 984169689Skan{ 985169689Skan tree finally_stmts = NULL_TREE; 986169689Skan tree_stmt_iterator initially_stmts = tsi_start (*stmt_list); 987169689Skan 988169689Skan while (decl != NULL_TREE) 989169689Skan { 990169689Skan if (mf_decl_eligible_p (decl) 991169689Skan /* Not already processed. */ 992169689Skan && ! mf_marked_p (decl) 993169689Skan /* Automatic variable. */ 994169689Skan && ! DECL_EXTERNAL (decl) 995169689Skan && ! TREE_STATIC (decl)) 996169689Skan { 997169689Skan tree size = NULL_TREE, variable_name; 998169689Skan tree unregister_fncall, unregister_fncall_params; 999169689Skan tree register_fncall, register_fncall_params; 1000169689Skan 1001169689Skan size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl))); 1002169689Skan 1003169689Skan /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */ 1004169689Skan unregister_fncall_params = 1005169689Skan tree_cons (NULL_TREE, 1006169689Skan convert (ptr_type_node, 1007169689Skan mf_mark (build1 (ADDR_EXPR, 1008169689Skan build_pointer_type (TREE_TYPE (decl)), 1009169689Skan decl))), 1010169689Skan tree_cons (NULL_TREE, 1011169689Skan size, 1012169689Skan tree_cons (NULL_TREE, 1013169689Skan /* __MF_TYPE_STACK */ 1014169689Skan build_int_cst (NULL_TREE, 3), 1015169689Skan NULL_TREE))); 1016169689Skan /* __mf_unregister (...) */ 1017169689Skan unregister_fncall = build_function_call_expr (mf_unregister_fndecl, 1018169689Skan unregister_fncall_params); 1019169689Skan 1020169689Skan /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK, "name") */ 1021169689Skan variable_name = mf_varname_tree (decl); 1022169689Skan register_fncall_params = 1023169689Skan tree_cons (NULL_TREE, 1024169689Skan convert (ptr_type_node, 1025169689Skan mf_mark (build1 (ADDR_EXPR, 1026169689Skan build_pointer_type (TREE_TYPE (decl)), 1027169689Skan decl))), 1028169689Skan tree_cons (NULL_TREE, 1029169689Skan size, 1030169689Skan tree_cons (NULL_TREE, 1031169689Skan /* __MF_TYPE_STACK */ 1032169689Skan build_int_cst (NULL_TREE, 3), 1033169689Skan tree_cons (NULL_TREE, 1034169689Skan variable_name, 1035169689Skan NULL_TREE)))); 1036169689Skan 1037169689Skan /* __mf_register (...) */ 1038169689Skan register_fncall = build_function_call_expr (mf_register_fndecl, 1039169689Skan register_fncall_params); 1040169689Skan 1041169689Skan /* Accumulate the two calls. */ 1042169689Skan /* ??? Set EXPR_LOCATION. */ 1043169689Skan gimplify_stmt (®ister_fncall); 1044169689Skan gimplify_stmt (&unregister_fncall); 1045169689Skan 1046169689Skan /* Add the __mf_register call at the current appending point. */ 1047169689Skan if (tsi_end_p (initially_stmts)) 1048169689Skan warning (0, "mudflap cannot track %qs in stub function", 1049169689Skan IDENTIFIER_POINTER (DECL_NAME (decl))); 1050169689Skan else 1051169689Skan { 1052169689Skan tsi_link_before (&initially_stmts, register_fncall, TSI_SAME_STMT); 1053169689Skan 1054169689Skan /* Accumulate the FINALLY piece. */ 1055169689Skan append_to_statement_list (unregister_fncall, &finally_stmts); 1056169689Skan } 1057169689Skan mf_mark (decl); 1058169689Skan } 1059169689Skan 1060169689Skan decl = TREE_CHAIN (decl); 1061169689Skan } 1062169689Skan 1063169689Skan /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */ 1064169689Skan if (finally_stmts != NULL_TREE) 1065169689Skan { 1066169689Skan tree t = build2 (TRY_FINALLY_EXPR, void_type_node, 1067169689Skan *stmt_list, finally_stmts); 1068169689Skan *stmt_list = NULL; 1069169689Skan append_to_statement_list (t, stmt_list); 1070169689Skan } 1071169689Skan} 1072169689Skan 1073169689Skan 1074169689Skan/* Process every variable mentioned in BIND_EXPRs. */ 1075169689Skanstatic tree 1076169689Skanmx_xfn_xform_decls (tree *t, int *continue_p, void *data) 1077169689Skan{ 1078169689Skan struct mf_xform_decls_data* d = (struct mf_xform_decls_data*) data; 1079169689Skan 1080169689Skan if (*t == NULL_TREE || *t == error_mark_node) 1081169689Skan { 1082169689Skan *continue_p = 0; 1083169689Skan return NULL_TREE; 1084169689Skan } 1085169689Skan 1086169689Skan *continue_p = 1; 1087169689Skan 1088169689Skan switch (TREE_CODE (*t)) 1089169689Skan { 1090169689Skan case BIND_EXPR: 1091169689Skan { 1092169689Skan /* Process function parameters now (but only once). */ 1093169689Skan mx_register_decls (d->param_decls, &BIND_EXPR_BODY (*t)); 1094169689Skan d->param_decls = NULL_TREE; 1095169689Skan 1096169689Skan mx_register_decls (BIND_EXPR_VARS (*t), &BIND_EXPR_BODY (*t)); 1097169689Skan } 1098169689Skan break; 1099169689Skan 1100169689Skan default: 1101169689Skan break; 1102169689Skan } 1103169689Skan 1104169689Skan return NULL_TREE; 1105169689Skan} 1106169689Skan 1107169689Skan/* Perform the object lifetime tracking mudflap transform on the given function 1108169689Skan tree. The tree is mutated in place, with possibly copied subtree nodes. 1109169689Skan 1110169689Skan For every auto variable declared, if its address is ever taken 1111169689Skan within the function, then supply its lifetime to the mudflap 1112169689Skan runtime with the __mf_register and __mf_unregister calls. 1113169689Skan*/ 1114169689Skan 1115169689Skanstatic void 1116169689Skanmf_xform_decls (tree fnbody, tree fnparams) 1117169689Skan{ 1118169689Skan struct mf_xform_decls_data d; 1119169689Skan d.param_decls = fnparams; 1120169689Skan walk_tree_without_duplicates (&fnbody, mx_xfn_xform_decls, &d); 1121169689Skan} 1122169689Skan 1123169689Skan 1124169689Skan/* ------------------------------------------------------------------------ */ 1125169689Skan/* Externally visible mudflap functions. */ 1126169689Skan 1127169689Skan 1128169689Skan/* Mark and return the given tree node to prevent further mudflap 1129169689Skan transforms. */ 1130169689Skanstatic GTY ((param_is (union tree_node))) htab_t marked_trees = NULL; 1131169689Skan 1132169689Skantree 1133169689Skanmf_mark (tree t) 1134169689Skan{ 1135169689Skan void **slot; 1136169689Skan 1137169689Skan if (marked_trees == NULL) 1138169689Skan marked_trees = htab_create_ggc (31, htab_hash_pointer, htab_eq_pointer, NULL); 1139169689Skan 1140169689Skan slot = htab_find_slot (marked_trees, t, INSERT); 1141169689Skan *slot = t; 1142169689Skan return t; 1143169689Skan} 1144169689Skan 1145169689Skanint 1146169689Skanmf_marked_p (tree t) 1147169689Skan{ 1148169689Skan void *entry; 1149169689Skan 1150169689Skan if (marked_trees == NULL) 1151169689Skan return 0; 1152169689Skan 1153169689Skan entry = htab_find (marked_trees, t); 1154169689Skan return (entry != NULL); 1155169689Skan} 1156169689Skan 1157169689Skan/* Remember given node as a static of some kind: global data, 1158169689Skan function-scope static, or an anonymous constant. Its assembler 1159169689Skan label is given. */ 1160169689Skan 1161169689Skan/* A list of globals whose incomplete declarations we encountered. 1162169689Skan Instead of emitting the __mf_register call for them here, it's 1163169689Skan delayed until program finish time. If they're still incomplete by 1164169689Skan then, warnings are emitted. */ 1165169689Skan 1166169689Skanstatic GTY (()) VEC(tree,gc) *deferred_static_decls; 1167169689Skan 1168169689Skan/* A list of statements for calling __mf_register() at startup time. */ 1169169689Skanstatic GTY (()) tree enqueued_call_stmt_chain; 1170169689Skan 1171169689Skanstatic void 1172169689Skanmudflap_register_call (tree obj, tree object_size, tree varname) 1173169689Skan{ 1174169689Skan tree arg, args, call_stmt; 1175169689Skan 1176169689Skan args = tree_cons (NULL_TREE, varname, NULL_TREE); 1177169689Skan 1178169689Skan arg = build_int_cst (NULL_TREE, 4); /* __MF_TYPE_STATIC */ 1179169689Skan args = tree_cons (NULL_TREE, arg, args); 1180169689Skan 1181169689Skan arg = convert (size_type_node, object_size); 1182169689Skan args = tree_cons (NULL_TREE, arg, args); 1183169689Skan 1184169689Skan arg = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (obj)), obj); 1185169689Skan arg = convert (ptr_type_node, arg); 1186169689Skan args = tree_cons (NULL_TREE, arg, args); 1187169689Skan 1188169689Skan call_stmt = build_function_call_expr (mf_register_fndecl, args); 1189169689Skan 1190169689Skan append_to_statement_list (call_stmt, &enqueued_call_stmt_chain); 1191169689Skan} 1192169689Skan 1193169689Skanvoid 1194169689Skanmudflap_enqueue_decl (tree obj) 1195169689Skan{ 1196169689Skan if (mf_marked_p (obj)) 1197169689Skan return; 1198169689Skan 1199169689Skan /* We don't need to process variable decls that are internally 1200169689Skan generated extern. If we did, we'd end up with warnings for them 1201169689Skan during mudflap_finish_file (). That would confuse the user, 1202169689Skan since the text would refer to variables that don't show up in the 1203169689Skan user's source code. */ 1204169689Skan if (DECL_P (obj) && DECL_EXTERNAL (obj) && DECL_ARTIFICIAL (obj)) 1205169689Skan return; 1206169689Skan 1207169689Skan VEC_safe_push (tree, gc, deferred_static_decls, obj); 1208169689Skan} 1209169689Skan 1210169689Skan 1211169689Skanvoid 1212169689Skanmudflap_enqueue_constant (tree obj) 1213169689Skan{ 1214169689Skan tree object_size, varname; 1215169689Skan 1216169689Skan if (mf_marked_p (obj)) 1217169689Skan return; 1218169689Skan 1219169689Skan if (TREE_CODE (obj) == STRING_CST) 1220169689Skan object_size = build_int_cst (NULL_TREE, TREE_STRING_LENGTH (obj)); 1221169689Skan else 1222169689Skan object_size = size_in_bytes (TREE_TYPE (obj)); 1223169689Skan 1224169689Skan if (TREE_CODE (obj) == STRING_CST) 1225169689Skan varname = mf_build_string ("string literal"); 1226169689Skan else 1227169689Skan varname = mf_build_string ("constant"); 1228169689Skan 1229169689Skan mudflap_register_call (obj, object_size, varname); 1230169689Skan} 1231169689Skan 1232169689Skan 1233169689Skan/* Emit any file-wide instrumentation. */ 1234169689Skanvoid 1235169689Skanmudflap_finish_file (void) 1236169689Skan{ 1237169689Skan tree ctor_statements = NULL_TREE; 1238169689Skan 1239169689Skan /* No need to continue when there were errors. */ 1240169689Skan if (errorcount != 0 || sorrycount != 0) 1241169689Skan return; 1242169689Skan 1243169689Skan /* Insert a call to __mf_init. */ 1244169689Skan { 1245169689Skan tree call2_stmt = build_function_call_expr (mf_init_fndecl, NULL_TREE); 1246169689Skan append_to_statement_list (call2_stmt, &ctor_statements); 1247169689Skan } 1248169689Skan 1249169689Skan /* If appropriate, call __mf_set_options to pass along read-ignore mode. */ 1250169689Skan if (flag_mudflap_ignore_reads) 1251169689Skan { 1252169689Skan tree arg = tree_cons (NULL_TREE, 1253169689Skan mf_build_string ("-ignore-reads"), NULL_TREE); 1254169689Skan tree call_stmt = build_function_call_expr (mf_set_options_fndecl, arg); 1255169689Skan append_to_statement_list (call_stmt, &ctor_statements); 1256169689Skan } 1257169689Skan 1258169689Skan /* Process all enqueued object decls. */ 1259169689Skan if (deferred_static_decls) 1260169689Skan { 1261169689Skan size_t i; 1262169689Skan tree obj; 1263169689Skan for (i = 0; VEC_iterate (tree, deferred_static_decls, i, obj); i++) 1264169689Skan { 1265169689Skan gcc_assert (DECL_P (obj)); 1266169689Skan 1267169689Skan if (mf_marked_p (obj)) 1268169689Skan continue; 1269169689Skan 1270169689Skan /* Omit registration for static unaddressed objects. NB: 1271169689Skan Perform registration for non-static objects regardless of 1272169689Skan TREE_USED or TREE_ADDRESSABLE, because they may be used 1273169689Skan from other compilation units. */ 1274169689Skan if (! TREE_PUBLIC (obj) && ! TREE_ADDRESSABLE (obj)) 1275169689Skan continue; 1276169689Skan 1277169689Skan if (! COMPLETE_TYPE_P (TREE_TYPE (obj))) 1278169689Skan { 1279169689Skan warning (0, "mudflap cannot track unknown size extern %qs", 1280169689Skan IDENTIFIER_POINTER (DECL_NAME (obj))); 1281169689Skan continue; 1282169689Skan } 1283169689Skan 1284169689Skan mudflap_register_call (obj, 1285169689Skan size_in_bytes (TREE_TYPE (obj)), 1286169689Skan mf_varname_tree (obj)); 1287169689Skan } 1288169689Skan 1289169689Skan VEC_truncate (tree, deferred_static_decls, 0); 1290169689Skan } 1291169689Skan 1292169689Skan /* Append all the enqueued registration calls. */ 1293169689Skan if (enqueued_call_stmt_chain) 1294169689Skan { 1295169689Skan append_to_statement_list (enqueued_call_stmt_chain, &ctor_statements); 1296169689Skan enqueued_call_stmt_chain = NULL_TREE; 1297169689Skan } 1298169689Skan 1299169689Skan cgraph_build_static_cdtor ('I', ctor_statements, 1300169689Skan MAX_RESERVED_INIT_PRIORITY-1); 1301169689Skan} 1302169689Skan 1303169689Skan 1304169689Skanstatic bool 1305169689Skangate_mudflap (void) 1306169689Skan{ 1307169689Skan return flag_mudflap != 0; 1308169689Skan} 1309169689Skan 1310169689Skanstruct tree_opt_pass pass_mudflap_1 = 1311169689Skan{ 1312169689Skan "mudflap1", /* name */ 1313169689Skan gate_mudflap, /* gate */ 1314169689Skan execute_mudflap_function_decls, /* execute */ 1315169689Skan NULL, /* sub */ 1316169689Skan NULL, /* next */ 1317169689Skan 0, /* static_pass_number */ 1318169689Skan 0, /* tv_id */ 1319169689Skan PROP_gimple_any, /* properties_required */ 1320169689Skan 0, /* properties_provided */ 1321169689Skan 0, /* properties_destroyed */ 1322169689Skan 0, /* todo_flags_start */ 1323169689Skan TODO_dump_func, /* todo_flags_finish */ 1324169689Skan 0 /* letter */ 1325169689Skan}; 1326169689Skan 1327169689Skanstruct tree_opt_pass pass_mudflap_2 = 1328169689Skan{ 1329169689Skan "mudflap2", /* name */ 1330169689Skan gate_mudflap, /* gate */ 1331169689Skan execute_mudflap_function_ops, /* execute */ 1332169689Skan NULL, /* sub */ 1333169689Skan NULL, /* next */ 1334169689Skan 0, /* static_pass_number */ 1335169689Skan 0, /* tv_id */ 1336169689Skan PROP_gimple_leh, /* properties_required */ 1337169689Skan 0, /* properties_provided */ 1338169689Skan 0, /* properties_destroyed */ 1339169689Skan 0, /* todo_flags_start */ 1340169689Skan TODO_verify_flow | TODO_verify_stmts 1341169689Skan | TODO_dump_func, /* todo_flags_finish */ 1342169689Skan 0 /* letter */ 1343169689Skan}; 1344169689Skan 1345169689Skan#include "gt-tree-mudflap.h" 1346