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