annotate gcc/cp/vtable-class-hierarchy.c @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1 /* Copyright (C) 2012-2018 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
2
kono
parents:
diff changeset
3 This file is part of GCC.
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 GCC is free software; you can redistribute it and/or modify it
kono
parents:
diff changeset
6 under the terms of the GNU General Public License as published by
kono
parents:
diff changeset
7 the Free Software Foundation; either version 3, or (at your option)
kono
parents:
diff changeset
8 any later version.
kono
parents:
diff changeset
9
kono
parents:
diff changeset
10 GCC is distributed in the hope that it will be useful, but
kono
parents:
diff changeset
11 WITHOUT ANY WARRANTY; without even the implied warranty of
kono
parents:
diff changeset
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
kono
parents:
diff changeset
13 General Public License for more details.
kono
parents:
diff changeset
14
kono
parents:
diff changeset
15 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
16 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
17 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
18
kono
parents:
diff changeset
19 /* Virtual Table Pointer Security Pass - Detect corruption of vtable pointers
kono
parents:
diff changeset
20 before using them for virtual method dispatches. */
kono
parents:
diff changeset
21
kono
parents:
diff changeset
22 /* This file is part of the vtable security feature implementation.
kono
parents:
diff changeset
23 The vtable security feature is designed to detect when a virtual
kono
parents:
diff changeset
24 call is about to be made through an invalid vtable pointer
kono
parents:
diff changeset
25 (possibly due to data corruption or malicious attacks). The
kono
parents:
diff changeset
26 compiler finds every virtual call, and inserts a verification call
kono
parents:
diff changeset
27 before the virtual call. The verification call takes the actual
kono
parents:
diff changeset
28 vtable pointer value in the object through which the virtual call
kono
parents:
diff changeset
29 is being made, and compares the vtable pointer against a set of all
kono
parents:
diff changeset
30 valid vtable pointers that the object could contain (this set is
kono
parents:
diff changeset
31 based on the declared type of the object). If the pointer is in
kono
parents:
diff changeset
32 the valid set, execution is allowed to continue; otherwise the
kono
parents:
diff changeset
33 program is halted.
kono
parents:
diff changeset
34
kono
parents:
diff changeset
35 There are several pieces needed in order to make this work: 1. For
kono
parents:
diff changeset
36 every virtual class in the program (i.e. a class that contains
kono
parents:
diff changeset
37 virtual methods), we need to build the set of all possible valid
kono
parents:
diff changeset
38 vtables that an object of that class could point to. This includes
kono
parents:
diff changeset
39 vtables for any class(es) that inherit from the class under
kono
parents:
diff changeset
40 consideration. 2. For every such data set we build up, we need a
kono
parents:
diff changeset
41 way to find and reference the data set. This is complicated by the
kono
parents:
diff changeset
42 fact that the real vtable addresses are not known until runtime,
kono
parents:
diff changeset
43 when the program is loaded into memory, but we need to reference the
kono
parents:
diff changeset
44 sets at compile time when we are inserting verification calls into
kono
parents:
diff changeset
45 the program. 3. We need to find every virtual call in the program,
kono
parents:
diff changeset
46 and insert the verification call (with the appropriate arguments)
kono
parents:
diff changeset
47 before the virtual call. 4. We need some runtime library pieces:
kono
parents:
diff changeset
48 the code to build up the data sets at runtime; the code to actually
kono
parents:
diff changeset
49 perform the verification using the data sets; and some code to set
kono
parents:
diff changeset
50 protections on the data sets, so they themselves do not become
kono
parents:
diff changeset
51 hacker targets.
kono
parents:
diff changeset
52
kono
parents:
diff changeset
53 To find and reference the set of valid vtable pointers for any given
kono
parents:
diff changeset
54 virtual class, we create a special global varible for each virtual
kono
parents:
diff changeset
55 class. We refer to this as the "vtable map variable" for that
kono
parents:
diff changeset
56 class. The vtable map variable has the type "void *", and is
kono
parents:
diff changeset
57 initialized by the compiler to NULL. At runtime when the set of
kono
parents:
diff changeset
58 valid vtable pointers for a virtual class, e.g. class Foo, is built,
kono
parents:
diff changeset
59 the vtable map variable for class Foo is made to point to the set.
kono
parents:
diff changeset
60 During compile time, when the compiler is inserting verification
kono
parents:
diff changeset
61 calls into the program, it passes the vtable map variable for the
kono
parents:
diff changeset
62 appropriate class to the verification call, so that at runtime the
kono
parents:
diff changeset
63 verification call can find the appropriate data set.
kono
parents:
diff changeset
64
kono
parents:
diff changeset
65 The actual set of valid vtable pointers for a virtual class,
kono
parents:
diff changeset
66 e.g. class Foo, cannot be built until runtime, when the vtables get
kono
parents:
diff changeset
67 loaded into memory and their addresses are known. But the knowledge
kono
parents:
diff changeset
68 about which vtables belong in which class' hierarchy is only known
kono
parents:
diff changeset
69 at compile time. Therefore at compile time we collect class
kono
parents:
diff changeset
70 hierarchy and vtable information about every virtual class, and we
kono
parents:
diff changeset
71 generate calls to build up the data sets at runtime. To build the
kono
parents:
diff changeset
72 data sets, we call one of the functions we add to the runtime
kono
parents:
diff changeset
73 library, __VLTRegisterPair. __VLTRegisterPair takes two arguments,
kono
parents:
diff changeset
74 a vtable map variable and the address of a vtable. If the vtable
kono
parents:
diff changeset
75 map variable is currently NULL, it creates a new data set (hash
kono
parents:
diff changeset
76 table), makes the vtable map variable point to the new data set, and
kono
parents:
diff changeset
77 inserts the vtable address into the data set. If the vtable map
kono
parents:
diff changeset
78 variable is not NULL, it just inserts the vtable address into the
kono
parents:
diff changeset
79 data set. In order to make sure that our data sets are built before
kono
parents:
diff changeset
80 any verification calls happen, we create a special constructor
kono
parents:
diff changeset
81 initialization function for each compilation unit, give it a very
kono
parents:
diff changeset
82 high initialization priority, and insert all of our calls to
kono
parents:
diff changeset
83 __VLTRegisterPair into our special constructor initialization
kono
parents:
diff changeset
84 function.
kono
parents:
diff changeset
85
kono
parents:
diff changeset
86 The vtable verification feature is controlled by the flag
kono
parents:
diff changeset
87 '-fvtable-verify='. There are three flavors of this:
kono
parents:
diff changeset
88 '-fvtable-verify=std', '-fvtable-verify=preinit', and
kono
parents:
diff changeset
89 '-fvtable-verify=none'. If the option '-fvtable-verfy=preinit' is
kono
parents:
diff changeset
90 used, then our constructor initialization function gets put into the
kono
parents:
diff changeset
91 preinit array. This is necessary if there are data sets that need
kono
parents:
diff changeset
92 to be built very early in execution. If the constructor
kono
parents:
diff changeset
93 initialization function gets put into the preinit array, the we also
kono
parents:
diff changeset
94 add calls to __VLTChangePermission at the beginning and end of the
kono
parents:
diff changeset
95 function. The call at the beginning sets the permissions on the
kono
parents:
diff changeset
96 data sets and vtable map variables to read/write, and the one at the
kono
parents:
diff changeset
97 end makes them read-only. If the '-fvtable-verify=std' option is
kono
parents:
diff changeset
98 used, the constructor initialization functions are executed at their
kono
parents:
diff changeset
99 normal time, and the __VLTChangePermission calls are handled
kono
parents:
diff changeset
100 differently (see the comments in libstdc++-v3/libsupc++/vtv_rts.cc).
kono
parents:
diff changeset
101 The option '-fvtable-verify=none' turns off vtable verification.
kono
parents:
diff changeset
102
kono
parents:
diff changeset
103 This file contains code to find and record the class hierarchies for
kono
parents:
diff changeset
104 the virtual classes in a program, and all the vtables associated
kono
parents:
diff changeset
105 with each such class; to generate the vtable map variables; and to
kono
parents:
diff changeset
106 generate the constructor initialization function (with the calls to
kono
parents:
diff changeset
107 __VLTRegisterPair, and __VLTChangePermission). The main data
kono
parents:
diff changeset
108 structures used for collecting the class hierarchy data and
kono
parents:
diff changeset
109 building/maintaining the vtable map variable data are defined in
kono
parents:
diff changeset
110 gcc/vtable-verify.h, because they are used both here and in
kono
parents:
diff changeset
111 gcc/vtable-verify.c. */
kono
parents:
diff changeset
112
kono
parents:
diff changeset
113 #include "config.h"
kono
parents:
diff changeset
114 #include "system.h"
kono
parents:
diff changeset
115 #include "coretypes.h"
kono
parents:
diff changeset
116 #include "vtable-verify.h"
kono
parents:
diff changeset
117 #include "cp-tree.h"
kono
parents:
diff changeset
118 #include "stringpool.h"
kono
parents:
diff changeset
119 #include "cgraph.h"
kono
parents:
diff changeset
120 #include "output.h"
kono
parents:
diff changeset
121 #include "tree-iterator.h"
kono
parents:
diff changeset
122 #include "gimplify.h"
kono
parents:
diff changeset
123 #include "stor-layout.h"
kono
parents:
diff changeset
124
kono
parents:
diff changeset
125 static int num_calls_to_regset = 0;
kono
parents:
diff changeset
126 static int num_calls_to_regpair = 0;
kono
parents:
diff changeset
127 static int current_set_size;
kono
parents:
diff changeset
128
kono
parents:
diff changeset
129 /* Mark these specially since they need to be stored in precompiled
kono
parents:
diff changeset
130 header IR. */
kono
parents:
diff changeset
131 static GTY (()) vec<tree, va_gc> *vlt_saved_class_info;
kono
parents:
diff changeset
132 static GTY (()) tree vlt_register_pairs_fndecl = NULL_TREE;
kono
parents:
diff changeset
133 static GTY (()) tree vlt_register_set_fndecl = NULL_TREE;
kono
parents:
diff changeset
134
kono
parents:
diff changeset
135 struct work_node {
kono
parents:
diff changeset
136 struct vtv_graph_node *node;
kono
parents:
diff changeset
137 struct work_node *next;
kono
parents:
diff changeset
138 };
kono
parents:
diff changeset
139
kono
parents:
diff changeset
140 struct vtbl_map_node *vtable_find_or_create_map_decl (tree);
kono
parents:
diff changeset
141
kono
parents:
diff changeset
142 /* As part of vtable verification the compiler generates and inserts
kono
parents:
diff changeset
143 calls to __VLTVerifyVtablePointer, which is in libstdc++. This
kono
parents:
diff changeset
144 function builds and initializes the function decl that is used
kono
parents:
diff changeset
145 in generating those function calls.
kono
parents:
diff changeset
146
kono
parents:
diff changeset
147 In addition to __VLTVerifyVtablePointer there is also
kono
parents:
diff changeset
148 __VLTVerifyVtablePointerDebug which can be used in place of
kono
parents:
diff changeset
149 __VLTVerifyVtablePointer, and which takes extra parameters and
kono
parents:
diff changeset
150 outputs extra information, to help debug problems. The debug
kono
parents:
diff changeset
151 version of this function is generated and used if flag_vtv_debug is
kono
parents:
diff changeset
152 true.
kono
parents:
diff changeset
153
kono
parents:
diff changeset
154 The signatures for these functions are:
kono
parents:
diff changeset
155
kono
parents:
diff changeset
156 void * __VLTVerifyVtablePointer (void **, void*);
kono
parents:
diff changeset
157 void * __VLTVerifyVtablePointerDebug (void**, void *, char *, char *);
kono
parents:
diff changeset
158 */
kono
parents:
diff changeset
159
kono
parents:
diff changeset
160 void
kono
parents:
diff changeset
161 vtv_build_vtable_verify_fndecl (void)
kono
parents:
diff changeset
162 {
kono
parents:
diff changeset
163 tree func_type = NULL_TREE;
kono
parents:
diff changeset
164
kono
parents:
diff changeset
165 if (verify_vtbl_ptr_fndecl != NULL_TREE
kono
parents:
diff changeset
166 && TREE_CODE (verify_vtbl_ptr_fndecl) != ERROR_MARK)
kono
parents:
diff changeset
167 return;
kono
parents:
diff changeset
168
kono
parents:
diff changeset
169 if (flag_vtv_debug)
kono
parents:
diff changeset
170 {
kono
parents:
diff changeset
171 func_type = build_function_type_list (const_ptr_type_node,
kono
parents:
diff changeset
172 build_pointer_type (ptr_type_node),
kono
parents:
diff changeset
173 const_ptr_type_node,
kono
parents:
diff changeset
174 const_string_type_node,
kono
parents:
diff changeset
175 const_string_type_node,
kono
parents:
diff changeset
176 NULL_TREE);
kono
parents:
diff changeset
177 verify_vtbl_ptr_fndecl =
kono
parents:
diff changeset
178 build_lang_decl (FUNCTION_DECL,
kono
parents:
diff changeset
179 get_identifier ("__VLTVerifyVtablePointerDebug"),
kono
parents:
diff changeset
180 func_type);
kono
parents:
diff changeset
181 }
kono
parents:
diff changeset
182 else
kono
parents:
diff changeset
183 {
kono
parents:
diff changeset
184 func_type = build_function_type_list (const_ptr_type_node,
kono
parents:
diff changeset
185 build_pointer_type (ptr_type_node),
kono
parents:
diff changeset
186 const_ptr_type_node,
kono
parents:
diff changeset
187 NULL_TREE);
kono
parents:
diff changeset
188 verify_vtbl_ptr_fndecl =
kono
parents:
diff changeset
189 build_lang_decl (FUNCTION_DECL,
kono
parents:
diff changeset
190 get_identifier ("__VLTVerifyVtablePointer"),
kono
parents:
diff changeset
191 func_type);
kono
parents:
diff changeset
192 }
kono
parents:
diff changeset
193
kono
parents:
diff changeset
194 TREE_NOTHROW (verify_vtbl_ptr_fndecl) = 1;
kono
parents:
diff changeset
195 DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl)
kono
parents:
diff changeset
196 = tree_cons (get_identifier ("leaf"), NULL,
kono
parents:
diff changeset
197 DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl));
kono
parents:
diff changeset
198 DECL_PURE_P (verify_vtbl_ptr_fndecl) = 1;
kono
parents:
diff changeset
199 TREE_PUBLIC (verify_vtbl_ptr_fndecl) = 1;
kono
parents:
diff changeset
200 DECL_PRESERVE_P (verify_vtbl_ptr_fndecl) = 1;
kono
parents:
diff changeset
201 }
kono
parents:
diff changeset
202
kono
parents:
diff changeset
203 /* As part of vtable verification the compiler generates and inserts
kono
parents:
diff changeset
204 calls to __VLTRegisterSet and __VLTRegisterPair, which are in
kono
parents:
diff changeset
205 libsupc++. This function builds and initializes the function decls
kono
parents:
diff changeset
206 that are used in generating those function calls.
kono
parents:
diff changeset
207
kono
parents:
diff changeset
208 The signatures for these functions are:
kono
parents:
diff changeset
209
kono
parents:
diff changeset
210 void __VLTRegisterSetDebug (void **, const void *, std::size_t,
kono
parents:
diff changeset
211 size_t, void **);
kono
parents:
diff changeset
212
kono
parents:
diff changeset
213 void __VLTRegisterSet (void **, const void *, std::size_t,
kono
parents:
diff changeset
214 size_t, void **);
kono
parents:
diff changeset
215
kono
parents:
diff changeset
216 void __VLTRegisterPairDebug (void **, const void *, size_t,
kono
parents:
diff changeset
217 const void *, const char *, const char *);
kono
parents:
diff changeset
218
kono
parents:
diff changeset
219 void __VLTRegisterPair (void **, const void *, size_t, const void *);
kono
parents:
diff changeset
220 */
kono
parents:
diff changeset
221
kono
parents:
diff changeset
222 static void
kono
parents:
diff changeset
223 init_functions (void)
kono
parents:
diff changeset
224 {
kono
parents:
diff changeset
225 tree register_set_type;
kono
parents:
diff changeset
226 tree register_pairs_type;
kono
parents:
diff changeset
227
kono
parents:
diff changeset
228 if (vlt_register_set_fndecl != NULL_TREE)
kono
parents:
diff changeset
229 return;
kono
parents:
diff changeset
230
kono
parents:
diff changeset
231 gcc_assert (vlt_register_pairs_fndecl == NULL_TREE);
kono
parents:
diff changeset
232 gcc_assert (vlt_register_set_fndecl == NULL_TREE);
kono
parents:
diff changeset
233
kono
parents:
diff changeset
234 /* Build function decl for __VLTRegisterSet*. */
kono
parents:
diff changeset
235
kono
parents:
diff changeset
236 register_set_type = build_function_type_list
kono
parents:
diff changeset
237 (void_type_node,
kono
parents:
diff changeset
238 build_pointer_type (ptr_type_node),
kono
parents:
diff changeset
239 const_ptr_type_node,
kono
parents:
diff changeset
240 size_type_node,
kono
parents:
diff changeset
241 size_type_node,
kono
parents:
diff changeset
242 build_pointer_type (ptr_type_node),
kono
parents:
diff changeset
243 NULL_TREE);
kono
parents:
diff changeset
244
kono
parents:
diff changeset
245 if (flag_vtv_debug)
kono
parents:
diff changeset
246 vlt_register_set_fndecl = build_lang_decl
kono
parents:
diff changeset
247 (FUNCTION_DECL,
kono
parents:
diff changeset
248 get_identifier ("__VLTRegisterSetDebug"),
kono
parents:
diff changeset
249 register_set_type);
kono
parents:
diff changeset
250 else
kono
parents:
diff changeset
251 vlt_register_set_fndecl = build_lang_decl
kono
parents:
diff changeset
252 (FUNCTION_DECL,
kono
parents:
diff changeset
253 get_identifier ("__VLTRegisterSet"),
kono
parents:
diff changeset
254 register_set_type);
kono
parents:
diff changeset
255
kono
parents:
diff changeset
256
kono
parents:
diff changeset
257 TREE_NOTHROW (vlt_register_set_fndecl) = 1;
kono
parents:
diff changeset
258 DECL_ATTRIBUTES (vlt_register_set_fndecl) =
kono
parents:
diff changeset
259 tree_cons (get_identifier ("leaf"), NULL,
kono
parents:
diff changeset
260 DECL_ATTRIBUTES (vlt_register_set_fndecl));
kono
parents:
diff changeset
261 DECL_EXTERNAL(vlt_register_set_fndecl) = 1;
kono
parents:
diff changeset
262 TREE_PUBLIC (vlt_register_set_fndecl) = 1;
kono
parents:
diff changeset
263 DECL_PRESERVE_P (vlt_register_set_fndecl) = 1;
kono
parents:
diff changeset
264 SET_DECL_LANGUAGE (vlt_register_set_fndecl, lang_cplusplus);
kono
parents:
diff changeset
265
kono
parents:
diff changeset
266 /* Build function decl for __VLTRegisterPair*. */
kono
parents:
diff changeset
267
kono
parents:
diff changeset
268 if (flag_vtv_debug)
kono
parents:
diff changeset
269 {
kono
parents:
diff changeset
270 register_pairs_type = build_function_type_list (void_type_node,
kono
parents:
diff changeset
271 build_pointer_type
kono
parents:
diff changeset
272 (ptr_type_node),
kono
parents:
diff changeset
273 const_ptr_type_node,
kono
parents:
diff changeset
274 size_type_node,
kono
parents:
diff changeset
275 const_ptr_type_node,
kono
parents:
diff changeset
276 const_string_type_node,
kono
parents:
diff changeset
277 const_string_type_node,
kono
parents:
diff changeset
278 NULL_TREE);
kono
parents:
diff changeset
279
kono
parents:
diff changeset
280 vlt_register_pairs_fndecl = build_lang_decl
kono
parents:
diff changeset
281 (FUNCTION_DECL,
kono
parents:
diff changeset
282 get_identifier ("__VLTRegisterPairDebug"),
kono
parents:
diff changeset
283 register_pairs_type);
kono
parents:
diff changeset
284 }
kono
parents:
diff changeset
285 else
kono
parents:
diff changeset
286 {
kono
parents:
diff changeset
287 register_pairs_type = build_function_type_list (void_type_node,
kono
parents:
diff changeset
288 build_pointer_type
kono
parents:
diff changeset
289 (ptr_type_node),
kono
parents:
diff changeset
290 const_ptr_type_node,
kono
parents:
diff changeset
291 size_type_node,
kono
parents:
diff changeset
292 const_ptr_type_node,
kono
parents:
diff changeset
293 NULL_TREE);
kono
parents:
diff changeset
294
kono
parents:
diff changeset
295 vlt_register_pairs_fndecl = build_lang_decl
kono
parents:
diff changeset
296 (FUNCTION_DECL,
kono
parents:
diff changeset
297 get_identifier ("__VLTRegisterPair"),
kono
parents:
diff changeset
298 register_pairs_type);
kono
parents:
diff changeset
299 }
kono
parents:
diff changeset
300
kono
parents:
diff changeset
301 TREE_NOTHROW (vlt_register_pairs_fndecl) = 1;
kono
parents:
diff changeset
302 DECL_ATTRIBUTES (vlt_register_pairs_fndecl) =
kono
parents:
diff changeset
303 tree_cons (get_identifier ("leaf"), NULL,
kono
parents:
diff changeset
304 DECL_ATTRIBUTES (vlt_register_pairs_fndecl));
kono
parents:
diff changeset
305 DECL_EXTERNAL(vlt_register_pairs_fndecl) = 1;
kono
parents:
diff changeset
306 TREE_PUBLIC (vlt_register_pairs_fndecl) = 1;
kono
parents:
diff changeset
307 DECL_PRESERVE_P (vlt_register_pairs_fndecl) = 1;
kono
parents:
diff changeset
308 SET_DECL_LANGUAGE (vlt_register_pairs_fndecl, lang_cplusplus);
kono
parents:
diff changeset
309
kono
parents:
diff changeset
310 }
kono
parents:
diff changeset
311
kono
parents:
diff changeset
312 /* This is a helper function for
kono
parents:
diff changeset
313 vtv_compute_class_hierarchy_transitive_closure. It adds a
kono
parents:
diff changeset
314 vtv_graph_node to the WORKLIST, which is a linked list of
kono
parents:
diff changeset
315 seen-but-not-yet-processed nodes. INSERTED is a bitmap, one bit
kono
parents:
diff changeset
316 per node, to help make sure that we don't insert a node into the
kono
parents:
diff changeset
317 worklist more than once. Each node represents a class somewhere in
kono
parents:
diff changeset
318 our class hierarchy information. Every node in the graph gets added
kono
parents:
diff changeset
319 to the worklist exactly once and removed from the worklist exactly
kono
parents:
diff changeset
320 once (when all of its children have been processed). */
kono
parents:
diff changeset
321
kono
parents:
diff changeset
322 static void
kono
parents:
diff changeset
323 add_to_worklist (struct work_node **worklist, struct vtv_graph_node *node,
kono
parents:
diff changeset
324 sbitmap inserted)
kono
parents:
diff changeset
325 {
kono
parents:
diff changeset
326 struct work_node *new_work_node;
kono
parents:
diff changeset
327
kono
parents:
diff changeset
328 if (bitmap_bit_p (inserted, node->class_uid))
kono
parents:
diff changeset
329 return;
kono
parents:
diff changeset
330
kono
parents:
diff changeset
331 new_work_node = XNEW (struct work_node);
kono
parents:
diff changeset
332 new_work_node->next = *worklist;
kono
parents:
diff changeset
333 new_work_node->node = node;
kono
parents:
diff changeset
334 *worklist = new_work_node;
kono
parents:
diff changeset
335
kono
parents:
diff changeset
336 bitmap_set_bit (inserted, node->class_uid);
kono
parents:
diff changeset
337 }
kono
parents:
diff changeset
338
kono
parents:
diff changeset
339 /* This is a helper function for
kono
parents:
diff changeset
340 vtv_compute_class_hierarchy_transitive_closure. It goes through
kono
parents:
diff changeset
341 the WORKLIST of class hierarchy nodes looking for a "leaf" node,
kono
parents:
diff changeset
342 i.e. a node whose children in the hierarchy have all been
kono
parents:
diff changeset
343 processed. When it finds the next leaf node, it removes it from
kono
parents:
diff changeset
344 the linked list (WORKLIST) and returns the node. */
kono
parents:
diff changeset
345
kono
parents:
diff changeset
346 static struct vtv_graph_node *
kono
parents:
diff changeset
347 find_and_remove_next_leaf_node (struct work_node **worklist)
kono
parents:
diff changeset
348 {
kono
parents:
diff changeset
349 struct work_node *prev, *cur;
kono
parents:
diff changeset
350 struct vtv_graph_node *ret_val = NULL;
kono
parents:
diff changeset
351
kono
parents:
diff changeset
352 for (prev = NULL, cur = *worklist; cur; prev = cur, cur = cur->next)
kono
parents:
diff changeset
353 {
kono
parents:
diff changeset
354 if ((cur->node->children).length() == cur->node->num_processed_children)
kono
parents:
diff changeset
355 {
kono
parents:
diff changeset
356 if (prev == NULL)
kono
parents:
diff changeset
357 (*worklist) = cur->next;
kono
parents:
diff changeset
358 else
kono
parents:
diff changeset
359 prev->next = cur->next;
kono
parents:
diff changeset
360
kono
parents:
diff changeset
361 cur->next = NULL;
kono
parents:
diff changeset
362 ret_val = cur->node;
kono
parents:
diff changeset
363 free (cur);
kono
parents:
diff changeset
364 return ret_val;
kono
parents:
diff changeset
365 }
kono
parents:
diff changeset
366 }
kono
parents:
diff changeset
367
kono
parents:
diff changeset
368 return NULL;
kono
parents:
diff changeset
369 }
kono
parents:
diff changeset
370
kono
parents:
diff changeset
371 /* In our class hierarchy graph, each class node contains a bitmap,
kono
parents:
diff changeset
372 with one bit for each class in the hierarchy. The bits are set for
kono
parents:
diff changeset
373 classes that are descendants in the graph of the current node.
kono
parents:
diff changeset
374 Initially the descendants bitmap is only set for immediate
kono
parents:
diff changeset
375 descendants. This function traverses the class hierarchy graph,
kono
parents:
diff changeset
376 bottom up, filling in the transitive closures for the descendants
kono
parents:
diff changeset
377 as we rise up the graph. */
kono
parents:
diff changeset
378
kono
parents:
diff changeset
379 void
kono
parents:
diff changeset
380 vtv_compute_class_hierarchy_transitive_closure (void)
kono
parents:
diff changeset
381 {
kono
parents:
diff changeset
382 struct work_node *worklist = NULL;
kono
parents:
diff changeset
383 sbitmap inserted = sbitmap_alloc (num_vtable_map_nodes);
kono
parents:
diff changeset
384 unsigned i;
kono
parents:
diff changeset
385 unsigned j;
kono
parents:
diff changeset
386
kono
parents:
diff changeset
387 /* Note: Every node in the graph gets added to the worklist exactly
kono
parents:
diff changeset
388 once and removed from the worklist exactly once (when all of its
kono
parents:
diff changeset
389 children have been processed). Each node's children edges are
kono
parents:
diff changeset
390 followed exactly once, and each node's parent edges are followed
kono
parents:
diff changeset
391 exactly once. So this algorithm is roughly O(V + 2E), i.e.
kono
parents:
diff changeset
392 O(E + V). */
kono
parents:
diff changeset
393
kono
parents:
diff changeset
394 /* Set-up: */
kono
parents:
diff changeset
395 /* Find all the "leaf" nodes in the graph, and add them to the worklist. */
kono
parents:
diff changeset
396 bitmap_clear (inserted);
kono
parents:
diff changeset
397 for (j = 0; j < num_vtable_map_nodes; ++j)
kono
parents:
diff changeset
398 {
kono
parents:
diff changeset
399 struct vtbl_map_node *cur = vtbl_map_nodes_vec[j];
kono
parents:
diff changeset
400 if (cur->class_info
kono
parents:
diff changeset
401 && ((cur->class_info->children).length() == 0)
kono
parents:
diff changeset
402 && ! (bitmap_bit_p (inserted, cur->class_info->class_uid)))
kono
parents:
diff changeset
403 add_to_worklist (&worklist, cur->class_info, inserted);
kono
parents:
diff changeset
404 }
kono
parents:
diff changeset
405
kono
parents:
diff changeset
406 /* Main work: pull next leaf node off work list, process it, add its
kono
parents:
diff changeset
407 parents to the worklist, where a 'leaf' node is one that has no
kono
parents:
diff changeset
408 children, or all of its children have been processed. */
kono
parents:
diff changeset
409 while (worklist)
kono
parents:
diff changeset
410 {
kono
parents:
diff changeset
411 struct vtv_graph_node *temp_node =
kono
parents:
diff changeset
412 find_and_remove_next_leaf_node (&worklist);
kono
parents:
diff changeset
413
kono
parents:
diff changeset
414 gcc_assert (temp_node != NULL);
kono
parents:
diff changeset
415 temp_node->descendants = sbitmap_alloc (num_vtable_map_nodes);
kono
parents:
diff changeset
416 bitmap_clear (temp_node->descendants);
kono
parents:
diff changeset
417 bitmap_set_bit (temp_node->descendants, temp_node->class_uid);
kono
parents:
diff changeset
418 for (i = 0; i < (temp_node->children).length(); ++i)
kono
parents:
diff changeset
419 bitmap_ior (temp_node->descendants, temp_node->descendants,
kono
parents:
diff changeset
420 temp_node->children[i]->descendants);
kono
parents:
diff changeset
421 for (i = 0; i < (temp_node->parents).length(); ++i)
kono
parents:
diff changeset
422 {
kono
parents:
diff changeset
423 temp_node->parents[i]->num_processed_children =
kono
parents:
diff changeset
424 temp_node->parents[i]->num_processed_children + 1;
kono
parents:
diff changeset
425 if (!bitmap_bit_p (inserted, temp_node->parents[i]->class_uid))
kono
parents:
diff changeset
426 add_to_worklist (&worklist, temp_node->parents[i], inserted);
kono
parents:
diff changeset
427 }
kono
parents:
diff changeset
428 }
kono
parents:
diff changeset
429 }
kono
parents:
diff changeset
430
kono
parents:
diff changeset
431 /* Keep track of which pairs we have already created __VLTRegisterPair
kono
parents:
diff changeset
432 calls for, to prevent creating duplicate calls within the same
kono
parents:
diff changeset
433 compilation unit. VTABLE_DECL is the var decl for the vtable of
kono
parents:
diff changeset
434 the (descendant) class that we are adding to our class hierarchy
kono
parents:
diff changeset
435 data. VPTR_ADDRESS is an expression for calculating the correct
kono
parents:
diff changeset
436 offset into the vtable (VTABLE_DECL). It is the actual vtable
kono
parents:
diff changeset
437 pointer address that will be stored in our list of valid vtable
kono
parents:
diff changeset
438 pointers for BASE_CLASS. BASE_CLASS is the record_type node for
kono
parents:
diff changeset
439 the base class to whose hiearchy we want to add
kono
parents:
diff changeset
440 VPTR_ADDRESS. (VTABLE_DECL should be the vtable for BASE_CLASS or
kono
parents:
diff changeset
441 one of BASE_CLASS' descendents. */
kono
parents:
diff changeset
442
kono
parents:
diff changeset
443 static bool
kono
parents:
diff changeset
444 check_and_record_registered_pairs (tree vtable_decl, tree vptr_address,
kono
parents:
diff changeset
445 tree base_class)
kono
parents:
diff changeset
446 {
kono
parents:
diff changeset
447 unsigned offset;
kono
parents:
diff changeset
448 struct vtbl_map_node *base_vtable_map_node;
kono
parents:
diff changeset
449 bool inserted_something = false;
kono
parents:
diff changeset
450
kono
parents:
diff changeset
451
kono
parents:
diff changeset
452 if (TREE_CODE (vptr_address) == ADDR_EXPR
kono
parents:
diff changeset
453 && TREE_CODE (TREE_OPERAND (vptr_address, 0)) == MEM_REF)
kono
parents:
diff changeset
454 vptr_address = TREE_OPERAND (vptr_address, 0);
kono
parents:
diff changeset
455
kono
parents:
diff changeset
456 if (TREE_OPERAND_LENGTH (vptr_address) > 1)
kono
parents:
diff changeset
457 offset = TREE_INT_CST_LOW (TREE_OPERAND (vptr_address, 1));
kono
parents:
diff changeset
458 else
kono
parents:
diff changeset
459 offset = 0;
kono
parents:
diff changeset
460
kono
parents:
diff changeset
461 base_vtable_map_node = vtbl_map_get_node (TYPE_MAIN_VARIANT (base_class));
kono
parents:
diff changeset
462
kono
parents:
diff changeset
463 inserted_something = vtbl_map_node_registration_insert
kono
parents:
diff changeset
464 (base_vtable_map_node,
kono
parents:
diff changeset
465 vtable_decl,
kono
parents:
diff changeset
466 offset);
kono
parents:
diff changeset
467 return !inserted_something;
kono
parents:
diff changeset
468 }
kono
parents:
diff changeset
469
kono
parents:
diff changeset
470 /* Given an IDENTIFIER_NODE, build and return a string literal based on it. */
kono
parents:
diff changeset
471
kono
parents:
diff changeset
472 static tree
kono
parents:
diff changeset
473 build_string_from_id (tree identifier)
kono
parents:
diff changeset
474 {
kono
parents:
diff changeset
475 int len;
kono
parents:
diff changeset
476
kono
parents:
diff changeset
477 gcc_assert (TREE_CODE (identifier) == IDENTIFIER_NODE);
kono
parents:
diff changeset
478
kono
parents:
diff changeset
479 len = IDENTIFIER_LENGTH (identifier);
kono
parents:
diff changeset
480 return build_string_literal (len + 1, IDENTIFIER_POINTER (identifier));
kono
parents:
diff changeset
481 }
kono
parents:
diff changeset
482
kono
parents:
diff changeset
483 /* A class may contain secondary vtables in it, for various reasons.
kono
parents:
diff changeset
484 This function goes through the decl chain of a class record looking
kono
parents:
diff changeset
485 for any fields that point to secondary vtables, and adding calls to
kono
parents:
diff changeset
486 __VLTRegisterPair for the secondary vtable pointers.
kono
parents:
diff changeset
487
kono
parents:
diff changeset
488 BASE_CLASS_DECL_ARG is an expression for the address of the vtable
kono
parents:
diff changeset
489 map variable for the BASE_CLASS (whose hierarchy we are currently
kono
parents:
diff changeset
490 updating). BASE_CLASS is the record_type node for the base class.
kono
parents:
diff changeset
491 RECORD_TYPE is the record_type node for the descendant class that
kono
parents:
diff changeset
492 we are possibly adding to BASE_CLASS's hierarchy. BODY is the
kono
parents:
diff changeset
493 function body for the constructor init function to which we are
kono
parents:
diff changeset
494 adding our calls to __VLTRegisterPair. */
kono
parents:
diff changeset
495
kono
parents:
diff changeset
496 static void
kono
parents:
diff changeset
497 register_construction_vtables (tree base_class, tree record_type,
kono
parents:
diff changeset
498 vec<tree> *vtable_ptr_array)
kono
parents:
diff changeset
499 {
kono
parents:
diff changeset
500 tree vtbl_var_decl;
kono
parents:
diff changeset
501
kono
parents:
diff changeset
502 if (TREE_CODE (record_type) != RECORD_TYPE)
kono
parents:
diff changeset
503 return;
kono
parents:
diff changeset
504
kono
parents:
diff changeset
505 vtbl_var_decl = CLASSTYPE_VTABLES (record_type);
kono
parents:
diff changeset
506
kono
parents:
diff changeset
507 if (CLASSTYPE_VBASECLASSES (record_type))
kono
parents:
diff changeset
508 {
kono
parents:
diff changeset
509 tree vtt_decl;
kono
parents:
diff changeset
510 bool already_registered = false;
kono
parents:
diff changeset
511 tree val_vtbl_decl = NULL_TREE;
kono
parents:
diff changeset
512
kono
parents:
diff changeset
513 vtt_decl = DECL_CHAIN (vtbl_var_decl);
kono
parents:
diff changeset
514
kono
parents:
diff changeset
515 /* Check to see if we have found a VTT. Add its data if appropriate. */
kono
parents:
diff changeset
516 if (vtt_decl)
kono
parents:
diff changeset
517 {
kono
parents:
diff changeset
518 tree values = DECL_INITIAL (vtt_decl);
kono
parents:
diff changeset
519 if (TREE_ASM_WRITTEN (vtt_decl)
kono
parents:
diff changeset
520 && values != NULL_TREE
kono
parents:
diff changeset
521 && TREE_CODE (values) == CONSTRUCTOR
kono
parents:
diff changeset
522 && TREE_CODE (TREE_TYPE (values)) == ARRAY_TYPE)
kono
parents:
diff changeset
523 {
kono
parents:
diff changeset
524 unsigned HOST_WIDE_INT cnt;
kono
parents:
diff changeset
525 constructor_elt *ce;
kono
parents:
diff changeset
526
kono
parents:
diff changeset
527 /* Loop through the initialization values for this
kono
parents:
diff changeset
528 vtable to get all the correct vtable pointer
kono
parents:
diff changeset
529 addresses that we need to add to our set of valid
kono
parents:
diff changeset
530 vtable pointers for the current base class. This may
kono
parents:
diff changeset
531 result in adding more than just the element assigned
kono
parents:
diff changeset
532 to the primary vptr of the class, so we may end up
kono
parents:
diff changeset
533 with more vtable pointers than are strictly
kono
parents:
diff changeset
534 necessary. */
kono
parents:
diff changeset
535
kono
parents:
diff changeset
536 for (cnt = 0;
kono
parents:
diff changeset
537 vec_safe_iterate (CONSTRUCTOR_ELTS (values),
kono
parents:
diff changeset
538 cnt, &ce);
kono
parents:
diff changeset
539 cnt++)
kono
parents:
diff changeset
540 {
kono
parents:
diff changeset
541 tree value = ce->value;
kono
parents:
diff changeset
542
kono
parents:
diff changeset
543 /* Search for the ADDR_EXPR operand within the value. */
kono
parents:
diff changeset
544
kono
parents:
diff changeset
545 while (value
kono
parents:
diff changeset
546 && TREE_OPERAND (value, 0)
kono
parents:
diff changeset
547 && TREE_CODE (TREE_OPERAND (value, 0)) == ADDR_EXPR)
kono
parents:
diff changeset
548 value = TREE_OPERAND (value, 0);
kono
parents:
diff changeset
549
kono
parents:
diff changeset
550 /* The VAR_DECL for the vtable should be the first
kono
parents:
diff changeset
551 argument of the ADDR_EXPR, which is the first
kono
parents:
diff changeset
552 argument of value.*/
kono
parents:
diff changeset
553
kono
parents:
diff changeset
554 if (TREE_OPERAND (value, 0))
kono
parents:
diff changeset
555 val_vtbl_decl = TREE_OPERAND (value, 0);
kono
parents:
diff changeset
556
kono
parents:
diff changeset
557 while (!VAR_P (val_vtbl_decl)
kono
parents:
diff changeset
558 && TREE_OPERAND (val_vtbl_decl, 0))
kono
parents:
diff changeset
559 val_vtbl_decl = TREE_OPERAND (val_vtbl_decl, 0);
kono
parents:
diff changeset
560
kono
parents:
diff changeset
561 gcc_assert (VAR_P (val_vtbl_decl));
kono
parents:
diff changeset
562
kono
parents:
diff changeset
563 /* Check to see if we already have this vtable pointer in
kono
parents:
diff changeset
564 our valid set for this base class. */
kono
parents:
diff changeset
565
kono
parents:
diff changeset
566 already_registered = check_and_record_registered_pairs
kono
parents:
diff changeset
567 (val_vtbl_decl,
kono
parents:
diff changeset
568 value,
kono
parents:
diff changeset
569 base_class);
kono
parents:
diff changeset
570
kono
parents:
diff changeset
571 if (already_registered)
kono
parents:
diff changeset
572 continue;
kono
parents:
diff changeset
573
kono
parents:
diff changeset
574 /* Add this vtable pointer to our set of valid
kono
parents:
diff changeset
575 pointers for the base class. */
kono
parents:
diff changeset
576
kono
parents:
diff changeset
577 vtable_ptr_array->safe_push (value);
kono
parents:
diff changeset
578 current_set_size++;
kono
parents:
diff changeset
579 }
kono
parents:
diff changeset
580 }
kono
parents:
diff changeset
581 }
kono
parents:
diff changeset
582 }
kono
parents:
diff changeset
583 }
kono
parents:
diff changeset
584
kono
parents:
diff changeset
585 /* This function iterates through all the vtables it can find from the
kono
parents:
diff changeset
586 BINFO of a class, to make sure we have found ALL of the vtables
kono
parents:
diff changeset
587 that an object of that class could point to. Generate calls to
kono
parents:
diff changeset
588 __VLTRegisterPair for those vtable pointers that we find.
kono
parents:
diff changeset
589
kono
parents:
diff changeset
590 BINFO is the tree_binfo node for the BASE_CLASS. BODY is the
kono
parents:
diff changeset
591 function body for the constructor init function to which we are
kono
parents:
diff changeset
592 adding calls to __VLTRegisterPair. ARG1 is an expression for the
kono
parents:
diff changeset
593 address of the vtable map variable (for the BASE_CLASS), that will
kono
parents:
diff changeset
594 point to the updated data set. BASE_CLASS is the record_type node
kono
parents:
diff changeset
595 for the base class whose set of valid vtable pointers we are
kono
parents:
diff changeset
596 updating. STR1 and STR2 are all debugging information, to be passed
kono
parents:
diff changeset
597 as parameters to __VLTRegisterPairDebug. STR1 represents the name
kono
parents:
diff changeset
598 of the vtable map variable to be updated by the call. Similarly,
kono
parents:
diff changeset
599 STR2 represents the name of the class whose vtable pointer is being
kono
parents:
diff changeset
600 added to the hierarchy. */
kono
parents:
diff changeset
601
kono
parents:
diff changeset
602 static void
kono
parents:
diff changeset
603 register_other_binfo_vtables (tree binfo, tree base_class,
kono
parents:
diff changeset
604 vec<tree> *vtable_ptr_array)
kono
parents:
diff changeset
605 {
kono
parents:
diff changeset
606 unsigned ix;
kono
parents:
diff changeset
607 tree base_binfo;
kono
parents:
diff changeset
608 tree vtable_decl;
kono
parents:
diff changeset
609 bool already_registered;
kono
parents:
diff changeset
610
kono
parents:
diff changeset
611 if (binfo == NULL_TREE)
kono
parents:
diff changeset
612 return;
kono
parents:
diff changeset
613
kono
parents:
diff changeset
614 for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
kono
parents:
diff changeset
615 {
kono
parents:
diff changeset
616 if ((!BINFO_PRIMARY_P (base_binfo)
kono
parents:
diff changeset
617 || BINFO_VIRTUAL_P (base_binfo))
kono
parents:
diff changeset
618 && (vtable_decl = get_vtbl_decl_for_binfo (base_binfo)))
kono
parents:
diff changeset
619 {
kono
parents:
diff changeset
620 tree vtable_address = build_vtbl_address (base_binfo);
kono
parents:
diff changeset
621
kono
parents:
diff changeset
622 already_registered = check_and_record_registered_pairs
kono
parents:
diff changeset
623 (vtable_decl,
kono
parents:
diff changeset
624 vtable_address,
kono
parents:
diff changeset
625 base_class);
kono
parents:
diff changeset
626 if (!already_registered)
kono
parents:
diff changeset
627 {
kono
parents:
diff changeset
628 vtable_ptr_array->safe_push (vtable_address);
kono
parents:
diff changeset
629 current_set_size++;
kono
parents:
diff changeset
630 }
kono
parents:
diff changeset
631 }
kono
parents:
diff changeset
632
kono
parents:
diff changeset
633 register_other_binfo_vtables (base_binfo, base_class, vtable_ptr_array);
kono
parents:
diff changeset
634 }
kono
parents:
diff changeset
635 }
kono
parents:
diff changeset
636
kono
parents:
diff changeset
637 /* The set of valid vtable pointers for any given class are stored in
kono
parents:
diff changeset
638 a hash table. For reasons of efficiency, that hash table size is
kono
parents:
diff changeset
639 always a power of two. In order to try to prevent re-sizing the
kono
parents:
diff changeset
640 hash tables very often, we pass __VLTRegisterPair an initial guess
kono
parents:
diff changeset
641 as to the number of entries the hashtable will eventually need
kono
parents:
diff changeset
642 (rounded up to the nearest power of two). This function takes the
kono
parents:
diff changeset
643 class information we have collected for a particular class,
kono
parents:
diff changeset
644 CLASS_NODE, and calculates the hash table size guess. */
kono
parents:
diff changeset
645
kono
parents:
diff changeset
646 static int
kono
parents:
diff changeset
647 guess_num_vtable_pointers (struct vtv_graph_node *class_node)
kono
parents:
diff changeset
648 {
kono
parents:
diff changeset
649 tree vtbl;
kono
parents:
diff changeset
650 int total_num_vtbls = 0;
kono
parents:
diff changeset
651 int num_vtbls_power_of_two = 1;
kono
parents:
diff changeset
652 unsigned i;
kono
parents:
diff changeset
653
kono
parents:
diff changeset
654 for (i = 0; i < num_vtable_map_nodes; ++i)
kono
parents:
diff changeset
655 if (bitmap_bit_p (class_node->descendants, i))
kono
parents:
diff changeset
656 {
kono
parents:
diff changeset
657 tree class_type = vtbl_map_nodes_vec[i]->class_info->class_type;
kono
parents:
diff changeset
658 for (vtbl = CLASSTYPE_VTABLES (class_type); vtbl;
kono
parents:
diff changeset
659 vtbl = DECL_CHAIN (vtbl))
kono
parents:
diff changeset
660 {
kono
parents:
diff changeset
661 total_num_vtbls++;
kono
parents:
diff changeset
662 if (total_num_vtbls > num_vtbls_power_of_two)
kono
parents:
diff changeset
663 num_vtbls_power_of_two <<= 1;
kono
parents:
diff changeset
664 }
kono
parents:
diff changeset
665 }
kono
parents:
diff changeset
666 return num_vtbls_power_of_two;
kono
parents:
diff changeset
667 }
kono
parents:
diff changeset
668
kono
parents:
diff changeset
669 /* A simple hash function on strings */
kono
parents:
diff changeset
670 /* Be careful about changing this routine. The values generated will
kono
parents:
diff changeset
671 be stored in the calls to InitSet. So, changing this routine may
kono
parents:
diff changeset
672 cause a binary incompatibility. */
kono
parents:
diff changeset
673
kono
parents:
diff changeset
674 static uint32_t
kono
parents:
diff changeset
675 vtv_string_hash (const char *in)
kono
parents:
diff changeset
676 {
kono
parents:
diff changeset
677 const char *s = in;
kono
parents:
diff changeset
678 uint32_t h = 0;
kono
parents:
diff changeset
679
kono
parents:
diff changeset
680 gcc_assert (in != NULL);
kono
parents:
diff changeset
681 for ( ; *s; ++s)
kono
parents:
diff changeset
682 h = 5 * h + *s;
kono
parents:
diff changeset
683 return h;
kono
parents:
diff changeset
684 }
kono
parents:
diff changeset
685
kono
parents:
diff changeset
686 static char *
kono
parents:
diff changeset
687 get_log_file_name (const char *fname)
kono
parents:
diff changeset
688 {
kono
parents:
diff changeset
689 const char *tmp_dir = concat (dump_dir_name, NULL);
kono
parents:
diff changeset
690 char *full_name;
kono
parents:
diff changeset
691 int dir_len;
kono
parents:
diff changeset
692 int fname_len;
kono
parents:
diff changeset
693
kono
parents:
diff changeset
694 dir_len = strlen (tmp_dir);
kono
parents:
diff changeset
695 fname_len = strlen (fname);
kono
parents:
diff changeset
696
kono
parents:
diff changeset
697 full_name = XNEWVEC (char, dir_len + fname_len + 1);
kono
parents:
diff changeset
698 strcpy (full_name, tmp_dir);
kono
parents:
diff changeset
699 strcpy (full_name + dir_len, fname);
kono
parents:
diff changeset
700
kono
parents:
diff changeset
701 return full_name;
kono
parents:
diff changeset
702 }
kono
parents:
diff changeset
703
kono
parents:
diff changeset
704 static void
kono
parents:
diff changeset
705 write_out_current_set_data (tree base_class, int set_size)
kono
parents:
diff changeset
706 {
kono
parents:
diff changeset
707 static int class_data_log_fd = -1;
kono
parents:
diff changeset
708 char buffer[1024];
kono
parents:
diff changeset
709 int bytes_written __attribute__ ((unused));
kono
parents:
diff changeset
710 char *file_name = get_log_file_name ("vtv_class_set_sizes.log");
kono
parents:
diff changeset
711
kono
parents:
diff changeset
712 if (class_data_log_fd == -1)
kono
parents:
diff changeset
713 class_data_log_fd = open (file_name,
kono
parents:
diff changeset
714 O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);
kono
parents:
diff changeset
715
kono
parents:
diff changeset
716 if (class_data_log_fd == -1)
kono
parents:
diff changeset
717 {
kono
parents:
diff changeset
718 warning_at (UNKNOWN_LOCATION, 0,
kono
parents:
diff changeset
719 "unable to open log file %<vtv_class_set_sizes.log%>: %m");
kono
parents:
diff changeset
720 return;
kono
parents:
diff changeset
721 }
kono
parents:
diff changeset
722
kono
parents:
diff changeset
723 snprintf (buffer, sizeof (buffer), "%s %d\n",
kono
parents:
diff changeset
724 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (TYPE_NAME (base_class))),
kono
parents:
diff changeset
725 set_size);
kono
parents:
diff changeset
726 bytes_written = write (class_data_log_fd, buffer, strlen (buffer));
kono
parents:
diff changeset
727 }
kono
parents:
diff changeset
728
kono
parents:
diff changeset
729 static tree
kono
parents:
diff changeset
730 build_key_buffer_arg (tree base_ptr_var_decl)
kono
parents:
diff changeset
731 {
kono
parents:
diff changeset
732 const int key_type_fixed_size = 8;
kono
parents:
diff changeset
733 uint32_t len1 = IDENTIFIER_LENGTH (DECL_NAME (base_ptr_var_decl));
kono
parents:
diff changeset
734 uint32_t hash_value = vtv_string_hash (IDENTIFIER_POINTER
kono
parents:
diff changeset
735 (DECL_NAME (base_ptr_var_decl)));
kono
parents:
diff changeset
736 void *key_buffer = xmalloc (len1 + key_type_fixed_size);
kono
parents:
diff changeset
737 uint32_t *value_ptr = (uint32_t *) key_buffer;
kono
parents:
diff changeset
738 tree ret_value;
kono
parents:
diff changeset
739
kono
parents:
diff changeset
740 /* Set the len and hash for the string. */
kono
parents:
diff changeset
741 *value_ptr = len1;
kono
parents:
diff changeset
742 value_ptr++;
kono
parents:
diff changeset
743 *value_ptr = hash_value;
kono
parents:
diff changeset
744
kono
parents:
diff changeset
745 /* Now copy the string representation of the vtbl map name... */
kono
parents:
diff changeset
746 memcpy ((char *) key_buffer + key_type_fixed_size,
kono
parents:
diff changeset
747 IDENTIFIER_POINTER (DECL_NAME (base_ptr_var_decl)),
kono
parents:
diff changeset
748 len1);
kono
parents:
diff changeset
749
kono
parents:
diff changeset
750 /* ... and build a string literal from it. This will make a copy
kono
parents:
diff changeset
751 so the key_bufffer is not needed anymore after this. */
kono
parents:
diff changeset
752 ret_value = build_string_literal (len1 + key_type_fixed_size,
kono
parents:
diff changeset
753 (char *) key_buffer);
kono
parents:
diff changeset
754 free (key_buffer);
kono
parents:
diff changeset
755 return ret_value;
kono
parents:
diff changeset
756 }
kono
parents:
diff changeset
757
kono
parents:
diff changeset
758 static void
kono
parents:
diff changeset
759 insert_call_to_register_set (tree class_name,
kono
parents:
diff changeset
760 vec<tree> *vtbl_ptr_array, tree body, tree arg1,
kono
parents:
diff changeset
761 tree arg2, tree size_hint_arg)
kono
parents:
diff changeset
762 {
kono
parents:
diff changeset
763 tree call_expr;
kono
parents:
diff changeset
764 int num_args = vtbl_ptr_array->length();
kono
parents:
diff changeset
765 char *array_arg_name = ACONCAT (("__vptr_array_",
kono
parents:
diff changeset
766 IDENTIFIER_POINTER (class_name), NULL));
kono
parents:
diff changeset
767 tree array_arg_type = build_array_type_nelts (build_pointer_type
kono
parents:
diff changeset
768 (build_pointer_type
kono
parents:
diff changeset
769 (void_type_node)),
kono
parents:
diff changeset
770 num_args);
kono
parents:
diff changeset
771 tree array_arg = build_decl (UNKNOWN_LOCATION, VAR_DECL,
kono
parents:
diff changeset
772 get_identifier (array_arg_name),
kono
parents:
diff changeset
773 array_arg_type);
kono
parents:
diff changeset
774 int k;
kono
parents:
diff changeset
775
kono
parents:
diff changeset
776 vec<constructor_elt, va_gc> *array_elements;
kono
parents:
diff changeset
777 vec_alloc (array_elements, num_args);
kono
parents:
diff changeset
778
kono
parents:
diff changeset
779 tree initial = NULL_TREE;
kono
parents:
diff changeset
780 tree arg3 = NULL_TREE;
kono
parents:
diff changeset
781
kono
parents:
diff changeset
782 TREE_PUBLIC (array_arg) = 0;
kono
parents:
diff changeset
783 DECL_EXTERNAL (array_arg) = 0;
kono
parents:
diff changeset
784 TREE_STATIC (array_arg) = 1;
kono
parents:
diff changeset
785 DECL_ARTIFICIAL (array_arg) = 0;
kono
parents:
diff changeset
786 TREE_READONLY (array_arg) = 1;
kono
parents:
diff changeset
787 DECL_IGNORED_P (array_arg) = 0;
kono
parents:
diff changeset
788 DECL_PRESERVE_P (array_arg) = 0;
kono
parents:
diff changeset
789 DECL_VISIBILITY (array_arg) = VISIBILITY_HIDDEN;
kono
parents:
diff changeset
790
kono
parents:
diff changeset
791 for (k = 0; k < num_args; ++k)
kono
parents:
diff changeset
792 {
kono
parents:
diff changeset
793 CONSTRUCTOR_APPEND_ELT (array_elements, NULL_TREE, (*vtbl_ptr_array)[k]);
kono
parents:
diff changeset
794 }
kono
parents:
diff changeset
795
kono
parents:
diff changeset
796 initial = build_constructor (TREE_TYPE (array_arg), array_elements);
kono
parents:
diff changeset
797
kono
parents:
diff changeset
798 TREE_CONSTANT (initial) = 1;
kono
parents:
diff changeset
799 TREE_STATIC (initial) = 1;
kono
parents:
diff changeset
800 DECL_INITIAL (array_arg) = initial;
kono
parents:
diff changeset
801 relayout_decl (array_arg);
kono
parents:
diff changeset
802 varpool_node::finalize_decl (array_arg);
kono
parents:
diff changeset
803
kono
parents:
diff changeset
804 arg3 = build1 (ADDR_EXPR, TYPE_POINTER_TO (TREE_TYPE (array_arg)), array_arg);
kono
parents:
diff changeset
805
kono
parents:
diff changeset
806 TREE_TYPE (arg3) = build_pointer_type (TREE_TYPE (array_arg));
kono
parents:
diff changeset
807
kono
parents:
diff changeset
808 call_expr = build_call_expr (vlt_register_set_fndecl, 5, arg1,
kono
parents:
diff changeset
809 arg2, /* set_symbol_key */
kono
parents:
diff changeset
810 size_hint_arg, build_int_cst (size_type_node,
kono
parents:
diff changeset
811 num_args),
kono
parents:
diff changeset
812 arg3);
kono
parents:
diff changeset
813 append_to_statement_list (call_expr, &body);
kono
parents:
diff changeset
814 num_calls_to_regset++;
kono
parents:
diff changeset
815 }
kono
parents:
diff changeset
816
kono
parents:
diff changeset
817 static void
kono
parents:
diff changeset
818 insert_call_to_register_pair (vec<tree> *vtbl_ptr_array, tree arg1,
kono
parents:
diff changeset
819 tree arg2, tree size_hint_arg, tree str1,
kono
parents:
diff changeset
820 tree str2, tree body)
kono
parents:
diff changeset
821 {
kono
parents:
diff changeset
822 tree call_expr;
kono
parents:
diff changeset
823 int num_args = vtbl_ptr_array->length();
kono
parents:
diff changeset
824 tree vtable_address = NULL_TREE;
kono
parents:
diff changeset
825
kono
parents:
diff changeset
826 if (num_args == 0)
kono
parents:
diff changeset
827 vtable_address = build_int_cst (build_pointer_type (void_type_node), 0);
kono
parents:
diff changeset
828 else
kono
parents:
diff changeset
829 vtable_address = (*vtbl_ptr_array)[0];
kono
parents:
diff changeset
830
kono
parents:
diff changeset
831 if (flag_vtv_debug)
kono
parents:
diff changeset
832 call_expr = build_call_expr (vlt_register_pairs_fndecl, 6, arg1, arg2,
kono
parents:
diff changeset
833 size_hint_arg, vtable_address, str1, str2);
kono
parents:
diff changeset
834 else
kono
parents:
diff changeset
835 call_expr = build_call_expr (vlt_register_pairs_fndecl, 4, arg1, arg2,
kono
parents:
diff changeset
836 size_hint_arg, vtable_address);
kono
parents:
diff changeset
837
kono
parents:
diff changeset
838 append_to_statement_list (call_expr, &body);
kono
parents:
diff changeset
839 num_calls_to_regpair++;
kono
parents:
diff changeset
840 }
kono
parents:
diff changeset
841
kono
parents:
diff changeset
842 static void
kono
parents:
diff changeset
843 output_set_info (tree record_type, vec<tree> vtbl_ptr_array)
kono
parents:
diff changeset
844 {
kono
parents:
diff changeset
845 static int vtv_debug_log_fd = -1;
kono
parents:
diff changeset
846 char buffer[1024];
kono
parents:
diff changeset
847 int bytes_written __attribute__ ((unused));
kono
parents:
diff changeset
848 int array_len = vtbl_ptr_array.length();
kono
parents:
diff changeset
849 const char *class_name =
kono
parents:
diff changeset
850 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (TYPE_NAME (record_type)));
kono
parents:
diff changeset
851 char *file_name = get_log_file_name ("vtv_set_ptr_data.log");
kono
parents:
diff changeset
852
kono
parents:
diff changeset
853 if (vtv_debug_log_fd == -1)
kono
parents:
diff changeset
854 vtv_debug_log_fd = open (file_name,
kono
parents:
diff changeset
855 O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);
kono
parents:
diff changeset
856 if (vtv_debug_log_fd == -1)
kono
parents:
diff changeset
857 {
kono
parents:
diff changeset
858 warning_at (UNKNOWN_LOCATION, 0,
kono
parents:
diff changeset
859 "unable to open log file %<vtv_set_ptr_data.log%>: %m");
kono
parents:
diff changeset
860 return;
kono
parents:
diff changeset
861 }
kono
parents:
diff changeset
862
kono
parents:
diff changeset
863 for (int i = 0; i < array_len; ++i)
kono
parents:
diff changeset
864 {
kono
parents:
diff changeset
865 const char *vptr_name = "unknown";
kono
parents:
diff changeset
866 int vptr_offset = 0;
kono
parents:
diff changeset
867
kono
parents:
diff changeset
868 if (TREE_CODE (vtbl_ptr_array[i]) == POINTER_PLUS_EXPR)
kono
parents:
diff changeset
869 {
kono
parents:
diff changeset
870 tree arg0 = TREE_OPERAND (vtbl_ptr_array[i], 0);
kono
parents:
diff changeset
871 tree arg1 = TREE_OPERAND (vtbl_ptr_array[i], 1);
kono
parents:
diff changeset
872
kono
parents:
diff changeset
873 if (TREE_CODE (arg0) == ADDR_EXPR)
kono
parents:
diff changeset
874 arg0 = TREE_OPERAND (arg0, 0);
kono
parents:
diff changeset
875
kono
parents:
diff changeset
876 if (VAR_P (arg0))
kono
parents:
diff changeset
877 vptr_name = IDENTIFIER_POINTER (DECL_NAME (arg0));
kono
parents:
diff changeset
878
kono
parents:
diff changeset
879 if (TREE_CODE (arg1) == INTEGER_CST)
kono
parents:
diff changeset
880 vptr_offset = TREE_INT_CST_LOW (arg1);
kono
parents:
diff changeset
881 }
kono
parents:
diff changeset
882
kono
parents:
diff changeset
883 snprintf (buffer, sizeof (buffer), "%s %s %s + %d\n",
kono
parents:
diff changeset
884 main_input_filename, class_name, vptr_name, vptr_offset);
kono
parents:
diff changeset
885 bytes_written = write (vtv_debug_log_fd, buffer, strlen(buffer));
kono
parents:
diff changeset
886 }
kono
parents:
diff changeset
887
kono
parents:
diff changeset
888 }
kono
parents:
diff changeset
889
kono
parents:
diff changeset
890 /* This function goes through our internal class hierarchy & vtable
kono
parents:
diff changeset
891 pointer data structure and outputs calls to __VLTRegisterPair for
kono
parents:
diff changeset
892 every class-vptr pair (for those classes whose vtable would be
kono
parents:
diff changeset
893 output in the current compilation unit). These calls get put into
kono
parents:
diff changeset
894 our constructor initialization function. BODY is the function
kono
parents:
diff changeset
895 body, so far, of our constructor initialization function, to which we
kono
parents:
diff changeset
896 add the calls. */
kono
parents:
diff changeset
897
kono
parents:
diff changeset
898 static bool
kono
parents:
diff changeset
899 register_all_pairs (tree body)
kono
parents:
diff changeset
900 {
kono
parents:
diff changeset
901 bool registered_at_least_one = false;
kono
parents:
diff changeset
902 vec<tree> *vtbl_ptr_array = NULL;
kono
parents:
diff changeset
903 unsigned j;
kono
parents:
diff changeset
904
kono
parents:
diff changeset
905 for (j = 0; j < num_vtable_map_nodes; ++j)
kono
parents:
diff changeset
906 {
kono
parents:
diff changeset
907 struct vtbl_map_node *current = vtbl_map_nodes_vec[j];
kono
parents:
diff changeset
908 unsigned i = 0;
kono
parents:
diff changeset
909 tree base_class = current->class_info->class_type;
kono
parents:
diff changeset
910 tree base_ptr_var_decl = current->vtbl_map_decl;
kono
parents:
diff changeset
911 tree arg1;
kono
parents:
diff changeset
912 tree arg2;
kono
parents:
diff changeset
913 tree new_type;
kono
parents:
diff changeset
914 tree str1 = NULL_TREE;
kono
parents:
diff changeset
915 tree str2 = NULL_TREE;
kono
parents:
diff changeset
916 size_t size_hint;
kono
parents:
diff changeset
917 tree size_hint_arg;
kono
parents:
diff changeset
918
kono
parents:
diff changeset
919 gcc_assert (current->class_info != NULL);
kono
parents:
diff changeset
920
kono
parents:
diff changeset
921
kono
parents:
diff changeset
922 if (flag_vtv_debug)
kono
parents:
diff changeset
923 str1 = build_string_from_id (DECL_NAME (base_ptr_var_decl));
kono
parents:
diff changeset
924
kono
parents:
diff changeset
925 new_type = build_pointer_type (TREE_TYPE (base_ptr_var_decl));
kono
parents:
diff changeset
926 arg1 = build1 (ADDR_EXPR, new_type, base_ptr_var_decl);
kono
parents:
diff changeset
927
kono
parents:
diff changeset
928 /* We need a fresh vector for each iteration. */
kono
parents:
diff changeset
929 if (vtbl_ptr_array)
kono
parents:
diff changeset
930 vec_free (vtbl_ptr_array);
kono
parents:
diff changeset
931
kono
parents:
diff changeset
932 vec_alloc (vtbl_ptr_array, 10);
kono
parents:
diff changeset
933
kono
parents:
diff changeset
934 for (i = 0; i < num_vtable_map_nodes; ++i)
kono
parents:
diff changeset
935 if (bitmap_bit_p (current->class_info->descendants, i))
kono
parents:
diff changeset
936 {
kono
parents:
diff changeset
937 struct vtbl_map_node *vtbl_class_node = vtbl_map_nodes_vec[i];
kono
parents:
diff changeset
938 tree class_type = vtbl_class_node->class_info->class_type;
kono
parents:
diff changeset
939
kono
parents:
diff changeset
940 if (class_type
kono
parents:
diff changeset
941 && (TREE_CODE (class_type) == RECORD_TYPE))
kono
parents:
diff changeset
942 {
kono
parents:
diff changeset
943 bool already_registered;
kono
parents:
diff changeset
944
kono
parents:
diff changeset
945 tree binfo = TYPE_BINFO (class_type);
kono
parents:
diff changeset
946 tree vtable_decl;
kono
parents:
diff changeset
947 bool vtable_should_be_output = false;
kono
parents:
diff changeset
948
kono
parents:
diff changeset
949 vtable_decl = CLASSTYPE_VTABLES (class_type);
kono
parents:
diff changeset
950
kono
parents:
diff changeset
951 /* Handle main vtable for this class. */
kono
parents:
diff changeset
952
kono
parents:
diff changeset
953 if (vtable_decl)
kono
parents:
diff changeset
954 {
kono
parents:
diff changeset
955 vtable_should_be_output = TREE_ASM_WRITTEN (vtable_decl);
kono
parents:
diff changeset
956 str2 = build_string_from_id (DECL_NAME (vtable_decl));
kono
parents:
diff changeset
957 }
kono
parents:
diff changeset
958
kono
parents:
diff changeset
959 if (vtable_decl && vtable_should_be_output)
kono
parents:
diff changeset
960 {
kono
parents:
diff changeset
961 tree vtable_address = build_vtbl_address (binfo);
kono
parents:
diff changeset
962
kono
parents:
diff changeset
963 already_registered = check_and_record_registered_pairs
kono
parents:
diff changeset
964 (vtable_decl,
kono
parents:
diff changeset
965 vtable_address,
kono
parents:
diff changeset
966 base_class);
kono
parents:
diff changeset
967
kono
parents:
diff changeset
968
kono
parents:
diff changeset
969 if (!already_registered)
kono
parents:
diff changeset
970 {
kono
parents:
diff changeset
971 vtbl_ptr_array->safe_push (vtable_address);
kono
parents:
diff changeset
972
kono
parents:
diff changeset
973 /* Find and handle any 'extra' vtables associated
kono
parents:
diff changeset
974 with this class, via virtual inheritance. */
kono
parents:
diff changeset
975 register_construction_vtables (base_class, class_type,
kono
parents:
diff changeset
976 vtbl_ptr_array);
kono
parents:
diff changeset
977
kono
parents:
diff changeset
978 /* Find and handle any 'extra' vtables associated
kono
parents:
diff changeset
979 with this class, via multiple inheritance. */
kono
parents:
diff changeset
980 register_other_binfo_vtables (binfo, base_class,
kono
parents:
diff changeset
981 vtbl_ptr_array);
kono
parents:
diff changeset
982 }
kono
parents:
diff changeset
983 }
kono
parents:
diff changeset
984 }
kono
parents:
diff changeset
985 }
kono
parents:
diff changeset
986 current_set_size = vtbl_ptr_array->length();
kono
parents:
diff changeset
987
kono
parents:
diff changeset
988 /* Sometimes we need to initialize the set symbol even if we are
kono
parents:
diff changeset
989 not adding any vtable pointers to the set in the current
kono
parents:
diff changeset
990 compilation unit. In that case, we need to initialize the
kono
parents:
diff changeset
991 set to our best guess as to what the eventual size of the set
kono
parents:
diff changeset
992 hash table will be (to prevent having to re-size the hash
kono
parents:
diff changeset
993 table later). */
kono
parents:
diff changeset
994
kono
parents:
diff changeset
995 size_hint = guess_num_vtable_pointers (current->class_info);
kono
parents:
diff changeset
996
kono
parents:
diff changeset
997 /* If we have added vtable pointers to the set in this
kono
parents:
diff changeset
998 compilation unit, adjust the size hint for the set's hash
kono
parents:
diff changeset
999 table appropriately. */
kono
parents:
diff changeset
1000 if (vtbl_ptr_array->length() > 0)
kono
parents:
diff changeset
1001 {
kono
parents:
diff changeset
1002 unsigned len = vtbl_ptr_array->length();
kono
parents:
diff changeset
1003 while ((size_t) len > size_hint)
kono
parents:
diff changeset
1004 size_hint <<= 1;
kono
parents:
diff changeset
1005 }
kono
parents:
diff changeset
1006 size_hint_arg = build_int_cst (size_type_node, size_hint);
kono
parents:
diff changeset
1007
kono
parents:
diff changeset
1008 /* Get the key-buffer argument. */
kono
parents:
diff changeset
1009 arg2 = build_key_buffer_arg (base_ptr_var_decl);
kono
parents:
diff changeset
1010
kono
parents:
diff changeset
1011 if (str2 == NULL_TREE)
kono
parents:
diff changeset
1012 str2 = build_string_literal (strlen ("unknown") + 1,
kono
parents:
diff changeset
1013 "unknown");
kono
parents:
diff changeset
1014
kono
parents:
diff changeset
1015 if (flag_vtv_debug)
kono
parents:
diff changeset
1016 output_set_info (current->class_info->class_type,
kono
parents:
diff changeset
1017 *vtbl_ptr_array);
kono
parents:
diff changeset
1018
kono
parents:
diff changeset
1019 if (vtbl_ptr_array->length() > 1)
kono
parents:
diff changeset
1020 {
kono
parents:
diff changeset
1021 insert_call_to_register_set (current->class_name,
kono
parents:
diff changeset
1022 vtbl_ptr_array, body, arg1, arg2,
kono
parents:
diff changeset
1023 size_hint_arg);
kono
parents:
diff changeset
1024 registered_at_least_one = true;
kono
parents:
diff changeset
1025 }
kono
parents:
diff changeset
1026 else
kono
parents:
diff changeset
1027 {
kono
parents:
diff changeset
1028
kono
parents:
diff changeset
1029 if (vtbl_ptr_array->length() > 0
kono
parents:
diff changeset
1030 || (current->is_used
kono
parents:
diff changeset
1031 || (current->registered->size() > 0)))
kono
parents:
diff changeset
1032 {
kono
parents:
diff changeset
1033 insert_call_to_register_pair (vtbl_ptr_array,
kono
parents:
diff changeset
1034 arg1, arg2, size_hint_arg, str1,
kono
parents:
diff changeset
1035 str2, body);
kono
parents:
diff changeset
1036 registered_at_least_one = true;
kono
parents:
diff changeset
1037 }
kono
parents:
diff changeset
1038 }
kono
parents:
diff changeset
1039
kono
parents:
diff changeset
1040 if (flag_vtv_counts && current_set_size > 0)
kono
parents:
diff changeset
1041 write_out_current_set_data (base_class, current_set_size);
kono
parents:
diff changeset
1042
kono
parents:
diff changeset
1043 }
kono
parents:
diff changeset
1044
kono
parents:
diff changeset
1045 return registered_at_least_one;
kono
parents:
diff changeset
1046 }
kono
parents:
diff changeset
1047
kono
parents:
diff changeset
1048 /* Given a tree containing a class type (CLASS_TYPE), this function
kono
parents:
diff changeset
1049 finds and returns the class hierarchy node for that class in our
kono
parents:
diff changeset
1050 data structure. */
kono
parents:
diff changeset
1051
kono
parents:
diff changeset
1052 static struct vtv_graph_node *
kono
parents:
diff changeset
1053 find_graph_node (tree class_type)
kono
parents:
diff changeset
1054 {
kono
parents:
diff changeset
1055 struct vtbl_map_node *vtbl_node;
kono
parents:
diff changeset
1056
kono
parents:
diff changeset
1057 vtbl_node = vtbl_map_get_node (TYPE_MAIN_VARIANT (class_type));
kono
parents:
diff changeset
1058 if (vtbl_node)
kono
parents:
diff changeset
1059 return vtbl_node->class_info;
kono
parents:
diff changeset
1060
kono
parents:
diff changeset
1061 return NULL;
kono
parents:
diff changeset
1062 }
kono
parents:
diff changeset
1063
kono
parents:
diff changeset
1064 /* Add base class/derived class pair to our internal class hierarchy
kono
parents:
diff changeset
1065 data structure. BASE_NODE is our vtv_graph_node that corresponds
kono
parents:
diff changeset
1066 to a base class. DERIVED_NODE is our vtv_graph_node that
kono
parents:
diff changeset
1067 corresponds to a class that is a descendant of the base class
kono
parents:
diff changeset
1068 (possibly the base class itself). */
kono
parents:
diff changeset
1069
kono
parents:
diff changeset
1070 static void
kono
parents:
diff changeset
1071 add_hierarchy_pair (struct vtv_graph_node *base_node,
kono
parents:
diff changeset
1072 struct vtv_graph_node *derived_node)
kono
parents:
diff changeset
1073 {
kono
parents:
diff changeset
1074 (base_node->children).safe_push (derived_node);
kono
parents:
diff changeset
1075 (derived_node->parents).safe_push (base_node);
kono
parents:
diff changeset
1076 }
kono
parents:
diff changeset
1077
kono
parents:
diff changeset
1078 /* This functions adds a new base class/derived class relationship to
kono
parents:
diff changeset
1079 our class hierarchy data structure. Both parameters are trees
kono
parents:
diff changeset
1080 representing the class types, i.e. RECORD_TYPE trees.
kono
parents:
diff changeset
1081 DERIVED_CLASS can be the same as BASE_CLASS. */
kono
parents:
diff changeset
1082
kono
parents:
diff changeset
1083 static void
kono
parents:
diff changeset
1084 update_class_hierarchy_information (tree base_class,
kono
parents:
diff changeset
1085 tree derived_class)
kono
parents:
diff changeset
1086 {
kono
parents:
diff changeset
1087 struct vtv_graph_node *base_node = find_graph_node (base_class);
kono
parents:
diff changeset
1088 struct vtv_graph_node *derived_node = find_graph_node (derived_class);
kono
parents:
diff changeset
1089
kono
parents:
diff changeset
1090 add_hierarchy_pair (base_node, derived_node);
kono
parents:
diff changeset
1091 }
kono
parents:
diff changeset
1092
kono
parents:
diff changeset
1093
kono
parents:
diff changeset
1094 static void
kono
parents:
diff changeset
1095 write_out_vtv_count_data (void)
kono
parents:
diff changeset
1096 {
kono
parents:
diff changeset
1097 static int vtv_count_log_fd = -1;
kono
parents:
diff changeset
1098 char buffer[1024];
kono
parents:
diff changeset
1099 int unused_vtbl_map_vars = 0;
kono
parents:
diff changeset
1100 int bytes_written __attribute__ ((unused));
kono
parents:
diff changeset
1101 char *file_name = get_log_file_name ("vtv_count_data.log");
kono
parents:
diff changeset
1102
kono
parents:
diff changeset
1103 if (vtv_count_log_fd == -1)
kono
parents:
diff changeset
1104 vtv_count_log_fd = open (file_name,
kono
parents:
diff changeset
1105 O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);
kono
parents:
diff changeset
1106 if (vtv_count_log_fd == -1)
kono
parents:
diff changeset
1107 {
kono
parents:
diff changeset
1108 warning_at (UNKNOWN_LOCATION, 0,
kono
parents:
diff changeset
1109 "unable to open log file %<vtv_count_data.log%>: %m");
kono
parents:
diff changeset
1110 return;
kono
parents:
diff changeset
1111 }
kono
parents:
diff changeset
1112
kono
parents:
diff changeset
1113 for (unsigned i = 0; i < num_vtable_map_nodes; ++i)
kono
parents:
diff changeset
1114 {
kono
parents:
diff changeset
1115 struct vtbl_map_node *current = vtbl_map_nodes_vec[i];
kono
parents:
diff changeset
1116 if (!current->is_used
kono
parents:
diff changeset
1117 && current->registered->size() == 0)
kono
parents:
diff changeset
1118 unused_vtbl_map_vars++;
kono
parents:
diff changeset
1119 }
kono
parents:
diff changeset
1120
kono
parents:
diff changeset
1121 snprintf (buffer, sizeof (buffer), "%s %d %d %d %d %d\n",
kono
parents:
diff changeset
1122 main_input_filename, total_num_virtual_calls,
kono
parents:
diff changeset
1123 total_num_verified_vcalls, num_calls_to_regset,
kono
parents:
diff changeset
1124 num_calls_to_regpair, unused_vtbl_map_vars);
kono
parents:
diff changeset
1125
kono
parents:
diff changeset
1126 bytes_written = write (vtv_count_log_fd, buffer, strlen (buffer));
kono
parents:
diff changeset
1127 }
kono
parents:
diff changeset
1128
kono
parents:
diff changeset
1129 /* This function calls register_all_pairs, which actually generates
kono
parents:
diff changeset
1130 all the calls to __VLTRegisterPair (in the verification constructor
kono
parents:
diff changeset
1131 init function). It also generates the calls to
kono
parents:
diff changeset
1132 __VLTChangePermission, if the verification constructor init
kono
parents:
diff changeset
1133 function is going into the preinit array. INIT_ROUTINE_BODY is
kono
parents:
diff changeset
1134 the body of our constructior initialization function, to which we
kono
parents:
diff changeset
1135 add our function calls.*/
kono
parents:
diff changeset
1136
kono
parents:
diff changeset
1137 bool
kono
parents:
diff changeset
1138 vtv_register_class_hierarchy_information (tree init_routine_body)
kono
parents:
diff changeset
1139 {
kono
parents:
diff changeset
1140 bool registered_something = false;
kono
parents:
diff changeset
1141
kono
parents:
diff changeset
1142 init_functions ();
kono
parents:
diff changeset
1143
kono
parents:
diff changeset
1144 if (num_vtable_map_nodes == 0)
kono
parents:
diff changeset
1145 return false;
kono
parents:
diff changeset
1146
kono
parents:
diff changeset
1147 /* Add class hierarchy pairs to the vtable map data structure. */
kono
parents:
diff changeset
1148 registered_something = register_all_pairs (init_routine_body);
kono
parents:
diff changeset
1149
kono
parents:
diff changeset
1150 if (flag_vtv_counts)
kono
parents:
diff changeset
1151 write_out_vtv_count_data ();
kono
parents:
diff changeset
1152
kono
parents:
diff changeset
1153 return registered_something;
kono
parents:
diff changeset
1154 }
kono
parents:
diff changeset
1155
kono
parents:
diff changeset
1156
kono
parents:
diff changeset
1157 /* Generate the special constructor function that calls
kono
parents:
diff changeset
1158 __VLTChangePermission and __VLTRegisterPairs, and give it a very
kono
parents:
diff changeset
1159 high initialization priority. */
kono
parents:
diff changeset
1160
kono
parents:
diff changeset
1161 void
kono
parents:
diff changeset
1162 vtv_generate_init_routine (void)
kono
parents:
diff changeset
1163 {
kono
parents:
diff changeset
1164 tree init_routine_body;
kono
parents:
diff changeset
1165 bool vtable_classes_found = false;
kono
parents:
diff changeset
1166
kono
parents:
diff changeset
1167 push_lang_context (lang_name_c);
kono
parents:
diff changeset
1168
kono
parents:
diff changeset
1169 /* The priority for this init function (constructor) is carefully
kono
parents:
diff changeset
1170 chosen so that it will happen after the calls to unprotect the
kono
parents:
diff changeset
1171 memory used for vtable verification and before the memory is
kono
parents:
diff changeset
1172 protected again. */
kono
parents:
diff changeset
1173 init_routine_body = vtv_start_verification_constructor_init_function ();
kono
parents:
diff changeset
1174
kono
parents:
diff changeset
1175 vtable_classes_found =
kono
parents:
diff changeset
1176 vtv_register_class_hierarchy_information (init_routine_body);
kono
parents:
diff changeset
1177
kono
parents:
diff changeset
1178 if (vtable_classes_found)
kono
parents:
diff changeset
1179 {
kono
parents:
diff changeset
1180 tree vtv_fndecl =
kono
parents:
diff changeset
1181 vtv_finish_verification_constructor_init_function (init_routine_body);
kono
parents:
diff changeset
1182 TREE_STATIC (vtv_fndecl) = 1;
kono
parents:
diff changeset
1183 TREE_USED (vtv_fndecl) = 1;
kono
parents:
diff changeset
1184 DECL_PRESERVE_P (vtv_fndecl) = 1;
kono
parents:
diff changeset
1185 /* We are running too late to generate any meaningful debug information
kono
parents:
diff changeset
1186 for this routine. */
kono
parents:
diff changeset
1187 DECL_IGNORED_P (vtv_fndecl) = 1;
kono
parents:
diff changeset
1188 if (flag_vtable_verify == VTV_PREINIT_PRIORITY && !TARGET_PECOFF)
kono
parents:
diff changeset
1189 DECL_STATIC_CONSTRUCTOR (vtv_fndecl) = 0;
kono
parents:
diff changeset
1190
kono
parents:
diff changeset
1191 gimplify_function_tree (vtv_fndecl);
kono
parents:
diff changeset
1192 cgraph_node::add_new_function (vtv_fndecl, false);
kono
parents:
diff changeset
1193
kono
parents:
diff changeset
1194 symtab->process_new_functions ();
kono
parents:
diff changeset
1195
kono
parents:
diff changeset
1196 if (flag_vtable_verify == VTV_PREINIT_PRIORITY && !TARGET_PECOFF)
kono
parents:
diff changeset
1197 assemble_vtv_preinit_initializer (vtv_fndecl);
kono
parents:
diff changeset
1198
kono
parents:
diff changeset
1199 }
kono
parents:
diff changeset
1200 pop_lang_context ();
kono
parents:
diff changeset
1201 }
kono
parents:
diff changeset
1202
kono
parents:
diff changeset
1203 /* This funtion takes a tree containing a class type (BASE_TYPE), and
kono
parents:
diff changeset
1204 it either finds the existing vtbl_map_node for that class in our
kono
parents:
diff changeset
1205 data structure, or it creates a new node and adds it to the data
kono
parents:
diff changeset
1206 structure if there is not one for the class already. As part of
kono
parents:
diff changeset
1207 this process it also creates the global vtable map variable for the
kono
parents:
diff changeset
1208 class. */
kono
parents:
diff changeset
1209
kono
parents:
diff changeset
1210 struct vtbl_map_node *
kono
parents:
diff changeset
1211 vtable_find_or_create_map_decl (tree base_type)
kono
parents:
diff changeset
1212 {
kono
parents:
diff changeset
1213 char *var_name = NULL;
kono
parents:
diff changeset
1214 struct vtbl_map_node *vtable_map_node = NULL;
kono
parents:
diff changeset
1215
kono
parents:
diff changeset
1216 /* Verify the type has an associated vtable. */
kono
parents:
diff changeset
1217 if (!TYPE_BINFO (base_type) || !BINFO_VTABLE (TYPE_BINFO (base_type)))
kono
parents:
diff changeset
1218 return NULL;
kono
parents:
diff changeset
1219
kono
parents:
diff changeset
1220 /* Create map lookup symbol for base class */
kono
parents:
diff changeset
1221 var_name = get_mangled_vtable_map_var_name (base_type);
kono
parents:
diff changeset
1222
kono
parents:
diff changeset
1223 /* We've already created the variable; just look it. */
kono
parents:
diff changeset
1224 vtable_map_node = vtbl_map_get_node (TYPE_MAIN_VARIANT (base_type));
kono
parents:
diff changeset
1225
kono
parents:
diff changeset
1226 if (!vtable_map_node || (vtable_map_node->vtbl_map_decl == NULL_TREE))
kono
parents:
diff changeset
1227 {
kono
parents:
diff changeset
1228 /* If we haven't already created the *__vtable_map global
kono
parents:
diff changeset
1229 variable for this class, do so now, and add it to the
kono
parents:
diff changeset
1230 varpool, to make sure it gets saved and written out. */
kono
parents:
diff changeset
1231
kono
parents:
diff changeset
1232 tree var_decl = NULL;
kono
parents:
diff changeset
1233 tree var_type = build_pointer_type (void_type_node);
kono
parents:
diff changeset
1234 tree initial_value = integer_zero_node;
kono
parents:
diff changeset
1235
kono
parents:
diff changeset
1236 var_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
kono
parents:
diff changeset
1237 get_identifier (var_name), var_type);
kono
parents:
diff changeset
1238
kono
parents:
diff changeset
1239 DECL_EXTERNAL (var_decl) = 0;
kono
parents:
diff changeset
1240 TREE_STATIC (var_decl) = 1;
kono
parents:
diff changeset
1241 DECL_VISIBILITY (var_decl) = VISIBILITY_HIDDEN;
kono
parents:
diff changeset
1242 SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (var_name));
kono
parents:
diff changeset
1243 DECL_ARTIFICIAL (var_decl) = 1;
kono
parents:
diff changeset
1244 /* We cannot mark this variable as read-only because we want to be
kono
parents:
diff changeset
1245 able to write to it at runtime. */
kono
parents:
diff changeset
1246 TREE_READONLY (var_decl) = 0;
kono
parents:
diff changeset
1247 DECL_IGNORED_P (var_decl) = 1;
kono
parents:
diff changeset
1248 DECL_PRESERVE_P (var_decl) = 1;
kono
parents:
diff changeset
1249
kono
parents:
diff changeset
1250 /* Put these mmap variables in thr .vtable_map_vars section, so
kono
parents:
diff changeset
1251 we can find and protect them. */
kono
parents:
diff changeset
1252
kono
parents:
diff changeset
1253 set_decl_section_name (var_decl, ".vtable_map_vars");
kono
parents:
diff changeset
1254 symtab_node::get (var_decl)->implicit_section = true;
kono
parents:
diff changeset
1255 DECL_INITIAL (var_decl) = initial_value;
kono
parents:
diff changeset
1256
kono
parents:
diff changeset
1257 comdat_linkage (var_decl);
kono
parents:
diff changeset
1258
kono
parents:
diff changeset
1259 varpool_node::finalize_decl (var_decl);
kono
parents:
diff changeset
1260 if (!vtable_map_node)
kono
parents:
diff changeset
1261 vtable_map_node =
kono
parents:
diff changeset
1262 find_or_create_vtbl_map_node (TYPE_MAIN_VARIANT (base_type));
kono
parents:
diff changeset
1263 if (vtable_map_node->vtbl_map_decl == NULL_TREE)
kono
parents:
diff changeset
1264 vtable_map_node->vtbl_map_decl = var_decl;
kono
parents:
diff changeset
1265 }
kono
parents:
diff changeset
1266
kono
parents:
diff changeset
1267 gcc_assert (vtable_map_node);
kono
parents:
diff changeset
1268 return vtable_map_node;
kono
parents:
diff changeset
1269 }
kono
parents:
diff changeset
1270
kono
parents:
diff changeset
1271 /* This function is used to build up our class hierarchy data for a
kono
parents:
diff changeset
1272 particular class. TYPE is the record_type tree node for the
kono
parents:
diff changeset
1273 class. */
kono
parents:
diff changeset
1274
kono
parents:
diff changeset
1275 static void
kono
parents:
diff changeset
1276 vtv_insert_single_class_info (tree type)
kono
parents:
diff changeset
1277 {
kono
parents:
diff changeset
1278 if (flag_vtable_verify)
kono
parents:
diff changeset
1279 {
kono
parents:
diff changeset
1280 tree binfo = TYPE_BINFO (type);
kono
parents:
diff changeset
1281 tree base_binfo;
kono
parents:
diff changeset
1282 struct vtbl_map_node *own_map;
kono
parents:
diff changeset
1283 int i;
kono
parents:
diff changeset
1284
kono
parents:
diff changeset
1285 /* First make sure to create the map for this record type. */
kono
parents:
diff changeset
1286 own_map = vtable_find_or_create_map_decl (type);
kono
parents:
diff changeset
1287 if (own_map == NULL)
kono
parents:
diff changeset
1288 return;
kono
parents:
diff changeset
1289
kono
parents:
diff changeset
1290 /* Go through the list of all base classes for the current
kono
parents:
diff changeset
1291 (derived) type, make sure the *__vtable_map global variable
kono
parents:
diff changeset
1292 for the base class exists, and add the base class/derived
kono
parents:
diff changeset
1293 class pair to the class hierarchy information we are
kono
parents:
diff changeset
1294 accumulating (for vtable pointer verification). */
kono
parents:
diff changeset
1295 for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
kono
parents:
diff changeset
1296 {
kono
parents:
diff changeset
1297 tree tree_val = BINFO_TYPE (base_binfo);
kono
parents:
diff changeset
1298 struct vtbl_map_node *vtable_map_node = NULL;
kono
parents:
diff changeset
1299
kono
parents:
diff changeset
1300 vtable_map_node = vtable_find_or_create_map_decl (tree_val);
kono
parents:
diff changeset
1301
kono
parents:
diff changeset
1302 if (vtable_map_node != NULL)
kono
parents:
diff changeset
1303 update_class_hierarchy_information (tree_val, type);
kono
parents:
diff changeset
1304 }
kono
parents:
diff changeset
1305 }
kono
parents:
diff changeset
1306 }
kono
parents:
diff changeset
1307
kono
parents:
diff changeset
1308 /* This function adds classes we are interested in to a list of
kono
parents:
diff changeset
1309 classes. RECORD is the record_type node for the class we are
kono
parents:
diff changeset
1310 adding to the list. */
kono
parents:
diff changeset
1311
kono
parents:
diff changeset
1312 void
kono
parents:
diff changeset
1313 vtv_save_class_info (tree record)
kono
parents:
diff changeset
1314 {
kono
parents:
diff changeset
1315 if (!flag_vtable_verify || TREE_CODE (record) == UNION_TYPE)
kono
parents:
diff changeset
1316 return;
kono
parents:
diff changeset
1317
kono
parents:
diff changeset
1318 if (!vlt_saved_class_info)
kono
parents:
diff changeset
1319 vec_alloc (vlt_saved_class_info, 10);
kono
parents:
diff changeset
1320
kono
parents:
diff changeset
1321 gcc_assert (TREE_CODE (record) == RECORD_TYPE);
kono
parents:
diff changeset
1322
kono
parents:
diff changeset
1323 vec_safe_push (vlt_saved_class_info, record);
kono
parents:
diff changeset
1324 }
kono
parents:
diff changeset
1325
kono
parents:
diff changeset
1326
kono
parents:
diff changeset
1327 /* This function goes through the list of classes we saved and calls
kono
parents:
diff changeset
1328 vtv_insert_single_class_info on each one, to build up our class
kono
parents:
diff changeset
1329 hierarchy data structure. */
kono
parents:
diff changeset
1330
kono
parents:
diff changeset
1331 void
kono
parents:
diff changeset
1332 vtv_recover_class_info (void)
kono
parents:
diff changeset
1333 {
kono
parents:
diff changeset
1334 tree current_class;
kono
parents:
diff changeset
1335 unsigned i;
kono
parents:
diff changeset
1336
kono
parents:
diff changeset
1337 if (vlt_saved_class_info)
kono
parents:
diff changeset
1338 {
kono
parents:
diff changeset
1339 for (i = 0; i < vlt_saved_class_info->length(); ++i)
kono
parents:
diff changeset
1340 {
kono
parents:
diff changeset
1341 current_class = (*vlt_saved_class_info)[i];
kono
parents:
diff changeset
1342 gcc_assert (TREE_CODE (current_class) == RECORD_TYPE);
kono
parents:
diff changeset
1343 vtv_insert_single_class_info (current_class);
kono
parents:
diff changeset
1344 }
kono
parents:
diff changeset
1345 }
kono
parents:
diff changeset
1346 }
kono
parents:
diff changeset
1347
kono
parents:
diff changeset
1348 #include "gt-cp-vtable-class-hierarchy.h"