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