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