Line data Source code
1 : /* Copyright (C) 2012-2023 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 12 : vtv_build_vtable_verify_fndecl (void)
162 : {
163 12 : tree func_type = NULL_TREE;
164 :
165 12 : if (verify_vtbl_ptr_fndecl != NULL_TREE
166 0 : && TREE_CODE (verify_vtbl_ptr_fndecl) != ERROR_MARK)
167 : return;
168 :
169 12 : 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 12 : 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 12 : verify_vtbl_ptr_fndecl =
189 12 : build_lang_decl (FUNCTION_DECL,
190 : get_identifier ("__VLTVerifyVtablePointer"),
191 : func_type);
192 : }
193 :
194 12 : TREE_NOTHROW (verify_vtbl_ptr_fndecl) = 1;
195 12 : DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl)
196 12 : = tree_cons (get_identifier ("leaf"), NULL,
197 12 : DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl));
198 12 : DECL_PURE_P (verify_vtbl_ptr_fndecl) = 1;
199 12 : TREE_PUBLIC (verify_vtbl_ptr_fndecl) = 1;
200 12 : 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 12 : init_functions (void)
224 : {
225 12 : tree register_set_type;
226 12 : tree register_pairs_type;
227 :
228 12 : if (vlt_register_set_fndecl != NULL_TREE)
229 : return;
230 :
231 12 : gcc_assert (vlt_register_pairs_fndecl == NULL_TREE);
232 12 : gcc_assert (vlt_register_set_fndecl == NULL_TREE);
233 :
234 : /* Build function decl for __VLTRegisterSet*. */
235 :
236 12 : register_set_type = build_function_type_list
237 12 : (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 12 : 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 12 : vlt_register_set_fndecl = build_lang_decl
252 12 : (FUNCTION_DECL,
253 : get_identifier ("__VLTRegisterSet"),
254 : register_set_type);
255 :
256 :
257 12 : TREE_NOTHROW (vlt_register_set_fndecl) = 1;
258 12 : DECL_ATTRIBUTES (vlt_register_set_fndecl) =
259 12 : tree_cons (get_identifier ("leaf"), NULL,
260 12 : DECL_ATTRIBUTES (vlt_register_set_fndecl));
261 12 : DECL_EXTERNAL(vlt_register_set_fndecl) = 1;
262 12 : TREE_PUBLIC (vlt_register_set_fndecl) = 1;
263 12 : DECL_PRESERVE_P (vlt_register_set_fndecl) = 1;
264 12 : SET_DECL_LANGUAGE (vlt_register_set_fndecl, lang_cplusplus);
265 :
266 : /* Build function decl for __VLTRegisterPair*. */
267 :
268 12 : 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 12 : 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 12 : vlt_register_pairs_fndecl = build_lang_decl
296 12 : (FUNCTION_DECL,
297 : get_identifier ("__VLTRegisterPair"),
298 : register_pairs_type);
299 : }
300 :
301 12 : TREE_NOTHROW (vlt_register_pairs_fndecl) = 1;
302 12 : DECL_ATTRIBUTES (vlt_register_pairs_fndecl) =
303 12 : tree_cons (get_identifier ("leaf"), NULL,
304 12 : DECL_ATTRIBUTES (vlt_register_pairs_fndecl));
305 12 : DECL_EXTERNAL(vlt_register_pairs_fndecl) = 1;
306 12 : TREE_PUBLIC (vlt_register_pairs_fndecl) = 1;
307 12 : DECL_PRESERVE_P (vlt_register_pairs_fndecl) = 1;
308 12 : 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 8 : add_to_worklist (struct work_node **worklist, struct vtv_graph_node *node,
324 : sbitmap inserted)
325 : {
326 8 : struct work_node *new_work_node;
327 :
328 8 : if (bitmap_bit_p (inserted, node->class_uid))
329 : return;
330 :
331 8 : new_work_node = XNEW (struct work_node);
332 8 : new_work_node->next = *worklist;
333 8 : new_work_node->node = node;
334 8 : *worklist = new_work_node;
335 :
336 8 : 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 8 : find_and_remove_next_leaf_node (struct work_node **worklist)
348 : {
349 8 : struct work_node *prev, *cur;
350 8 : struct vtv_graph_node *ret_val = NULL;
351 :
352 8 : for (prev = NULL, cur = *worklist; cur; prev = cur, cur = cur->next)
353 : {
354 16 : if ((cur->node->children).length() == cur->node->num_processed_children)
355 : {
356 8 : if (prev == NULL)
357 8 : (*worklist) = cur->next;
358 : else
359 0 : prev->next = cur->next;
360 :
361 8 : cur->next = NULL;
362 8 : ret_val = cur->node;
363 8 : free (cur);
364 8 : 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 12 : vtv_compute_class_hierarchy_transitive_closure (void)
381 : {
382 12 : struct work_node *worklist = NULL;
383 12 : sbitmap inserted = sbitmap_alloc (num_vtable_map_nodes);
384 12 : unsigned i;
385 12 : 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 12 : bitmap_clear (inserted);
397 20 : for (j = 0; j < num_vtable_map_nodes; ++j)
398 : {
399 8 : struct vtbl_map_node *cur = vtbl_map_nodes_vec[j];
400 8 : if (cur->class_info
401 8 : && ((cur->class_info->children).length() == 0)
402 16 : && ! (bitmap_bit_p (inserted, cur->class_info->class_uid)))
403 8 : 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 20 : while (worklist)
410 : {
411 8 : struct vtv_graph_node *temp_node =
412 8 : find_and_remove_next_leaf_node (&worklist);
413 :
414 8 : gcc_assert (temp_node != NULL);
415 8 : temp_node->descendants = sbitmap_alloc (num_vtable_map_nodes);
416 8 : bitmap_clear (temp_node->descendants);
417 8 : bitmap_set_bit (temp_node->descendants, temp_node->class_uid);
418 24 : 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 28 : 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 12 : }
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 8 : check_and_record_registered_pairs (tree vtable_decl, tree vptr_address,
445 : tree base_class)
446 : {
447 8 : unsigned offset;
448 8 : struct vtbl_map_node *base_vtable_map_node;
449 8 : bool inserted_something = false;
450 :
451 :
452 8 : if (TREE_CODE (vptr_address) == ADDR_EXPR
453 8 : && TREE_CODE (TREE_OPERAND (vptr_address, 0)) == MEM_REF)
454 4 : vptr_address = TREE_OPERAND (vptr_address, 0);
455 :
456 8 : if (TREE_OPERAND_LENGTH (vptr_address) > 1)
457 8 : offset = TREE_INT_CST_LOW (TREE_OPERAND (vptr_address, 1));
458 : else
459 : offset = 0;
460 :
461 8 : base_vtable_map_node = vtbl_map_get_node (TYPE_MAIN_VARIANT (base_class));
462 :
463 8 : inserted_something = vtbl_map_node_registration_insert
464 8 : (base_vtable_map_node,
465 : vtable_decl,
466 : offset);
467 8 : 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 4 : register_construction_vtables (tree base_class, tree record_type,
485 : vec<tree> *vtable_ptr_array)
486 : {
487 4 : tree vtbl_var_decl;
488 :
489 4 : if (TREE_CODE (record_type) != RECORD_TYPE)
490 : return;
491 :
492 4 : vtbl_var_decl = CLASSTYPE_VTABLES (record_type);
493 :
494 4 : if (CLASSTYPE_VBASECLASSES (record_type))
495 : {
496 4 : tree vtt_decl;
497 4 : bool already_registered = false;
498 4 : tree val_vtbl_decl = NULL_TREE;
499 :
500 4 : vtt_decl = DECL_CHAIN (vtbl_var_decl);
501 :
502 : /* Check to see if we have found a VTT. Add its data if appropriate. */
503 4 : if (vtt_decl)
504 : {
505 4 : tree values = DECL_INITIAL (vtt_decl);
506 4 : if (TREE_ASM_WRITTEN (vtt_decl)
507 4 : && values != NULL_TREE
508 4 : && TREE_CODE (values) == CONSTRUCTOR
509 8 : && 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 4 : for (cnt = 0;
524 8 : vec_safe_iterate (CONSTRUCTOR_ELTS (values),
525 : cnt, &ce);
526 : cnt++)
527 : {
528 4 : tree value = ce->value;
529 :
530 : /* Search for the ADDR_EXPR operand within the value. */
531 :
532 4 : while (value
533 4 : && TREE_OPERAND (value, 0)
534 8 : && 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 4 : if (TREE_OPERAND (value, 0))
542 4 : val_vtbl_decl = TREE_OPERAND (value, 0);
543 :
544 12 : while (!VAR_P (val_vtbl_decl)
545 12 : && TREE_OPERAND (val_vtbl_decl, 0))
546 8 : val_vtbl_decl = TREE_OPERAND (val_vtbl_decl, 0);
547 :
548 4 : 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 4 : already_registered = check_and_record_registered_pairs
554 4 : (val_vtbl_decl,
555 : value,
556 : base_class);
557 :
558 4 : if (already_registered)
559 4 : 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 8 : register_other_binfo_vtables (tree binfo, tree base_class,
591 : vec<tree> *vtable_ptr_array)
592 : {
593 8 : unsigned ix;
594 8 : tree base_binfo;
595 8 : tree vtable_decl;
596 8 : bool already_registered;
597 :
598 8 : if (binfo == NULL_TREE)
599 8 : return;
600 :
601 12 : for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
602 : {
603 4 : if ((!BINFO_PRIMARY_P (base_binfo)
604 0 : || BINFO_VIRTUAL_P (base_binfo))
605 4 : && (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 4 : 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 8 : guess_num_vtable_pointers (struct vtv_graph_node *class_node)
635 : {
636 8 : tree vtbl;
637 8 : int total_num_vtbls = 0;
638 8 : int num_vtbls_power_of_two = 1;
639 8 : unsigned i;
640 :
641 16 : for (i = 0; i < num_vtable_map_nodes; ++i)
642 8 : if (bitmap_bit_p (class_node->descendants, i))
643 : {
644 8 : tree class_type = vtbl_map_nodes_vec[i]->class_info->class_type;
645 24 : for (vtbl = CLASSTYPE_VTABLES (class_type); vtbl;
646 16 : vtbl = DECL_CHAIN (vtbl))
647 : {
648 16 : total_num_vtbls++;
649 16 : if (total_num_vtbls > num_vtbls_power_of_two)
650 8 : num_vtbls_power_of_two <<= 1;
651 : }
652 : }
653 8 : 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 8 : vtv_string_hash (const char *in)
663 : {
664 8 : const char *s = in;
665 8 : uint32_t h = 0;
666 :
667 8 : gcc_assert (in != NULL);
668 236 : for ( ; *s; ++s)
669 228 : h = 5 * h + *s;
670 8 : 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 8 : build_key_buffer_arg (tree base_ptr_var_decl)
718 : {
719 8 : const int key_type_fixed_size = 8;
720 8 : uint32_t len1 = IDENTIFIER_LENGTH (DECL_NAME (base_ptr_var_decl));
721 8 : uint32_t hash_value = vtv_string_hash (IDENTIFIER_POINTER
722 : (DECL_NAME (base_ptr_var_decl)));
723 8 : void *key_buffer = xmalloc (len1 + key_type_fixed_size);
724 8 : uint32_t *value_ptr = (uint32_t *) key_buffer;
725 8 : tree ret_value;
726 :
727 : /* Set the len and hash for the string. */
728 8 : *value_ptr = len1;
729 8 : value_ptr++;
730 8 : *value_ptr = hash_value;
731 :
732 : /* Now copy the string representation of the vtbl map name... */
733 16 : memcpy ((char *) key_buffer + key_type_fixed_size,
734 8 : 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 8 : ret_value = build_string_literal (len1 + key_type_fixed_size,
740 : (char *) key_buffer);
741 8 : free (key_buffer);
742 8 : 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 8 : 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 8 : tree call_expr;
810 8 : int num_args = vtbl_ptr_array->length();
811 12 : tree vtable_address = NULL_TREE;
812 :
813 8 : if (num_args == 0)
814 4 : vtable_address = build_int_cst (build_pointer_type (void_type_node), 0);
815 : else
816 4 : vtable_address = (*vtbl_ptr_array)[0];
817 :
818 8 : 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 8 : call_expr = build_call_expr (vlt_register_pairs_fndecl, 4, arg1, arg2,
823 : size_hint_arg, vtable_address);
824 :
825 8 : append_to_statement_list (call_expr, &body);
826 8 : num_calls_to_regpair++;
827 8 : }
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 8 : register_all_pairs (tree body)
887 : {
888 8 : bool registered_at_least_one = false;
889 8 : vec<tree> *vtbl_ptr_array = NULL;
890 8 : unsigned j;
891 :
892 16 : for (j = 0; j < num_vtable_map_nodes; ++j)
893 : {
894 8 : struct vtbl_map_node *current = vtbl_map_nodes_vec[j];
895 8 : unsigned i = 0;
896 8 : tree base_class = current->class_info->class_type;
897 8 : tree base_ptr_var_decl = current->vtbl_map_decl;
898 8 : tree arg1;
899 8 : tree arg2;
900 8 : tree new_type;
901 8 : tree str1 = NULL_TREE;
902 8 : tree str2 = NULL_TREE;
903 8 : size_t size_hint;
904 8 : tree size_hint_arg;
905 :
906 8 : gcc_assert (current->class_info != NULL);
907 :
908 :
909 8 : if (flag_vtv_debug)
910 0 : str1 = build_string_literal (DECL_NAME (base_ptr_var_decl));
911 :
912 8 : new_type = build_pointer_type (TREE_TYPE (base_ptr_var_decl));
913 8 : arg1 = build1 (ADDR_EXPR, new_type, base_ptr_var_decl);
914 :
915 : /* We need a fresh vector for each iteration. */
916 8 : if (vtbl_ptr_array)
917 0 : vec_free (vtbl_ptr_array);
918 :
919 8 : vec_alloc (vtbl_ptr_array, 10);
920 :
921 16 : for (i = 0; i < num_vtable_map_nodes; ++i)
922 8 : if (bitmap_bit_p (current->class_info->descendants, i))
923 : {
924 8 : struct vtbl_map_node *vtbl_class_node = vtbl_map_nodes_vec[i];
925 8 : tree class_type = vtbl_class_node->class_info->class_type;
926 :
927 8 : if (class_type
928 8 : && (TREE_CODE (class_type) == RECORD_TYPE))
929 : {
930 8 : bool already_registered;
931 :
932 8 : tree binfo = TYPE_BINFO (class_type);
933 8 : tree vtable_decl;
934 8 : bool vtable_should_be_output = false;
935 :
936 8 : vtable_decl = CLASSTYPE_VTABLES (class_type);
937 :
938 : /* Handle main vtable for this class. */
939 :
940 8 : if (vtable_decl)
941 : {
942 8 : vtable_should_be_output = TREE_ASM_WRITTEN (vtable_decl);
943 8 : str2 = build_string_literal (DECL_NAME (vtable_decl));
944 : }
945 :
946 8 : if (vtable_decl && vtable_should_be_output)
947 : {
948 4 : tree vtable_address = build_vtbl_address (binfo);
949 :
950 4 : already_registered = check_and_record_registered_pairs
951 4 : (vtable_decl,
952 : vtable_address,
953 : base_class);
954 :
955 :
956 4 : if (!already_registered)
957 : {
958 4 : vtbl_ptr_array->safe_push (vtable_address);
959 :
960 : /* Find and handle any 'extra' vtables associated
961 : with this class, via virtual inheritance. */
962 4 : 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 4 : register_other_binfo_vtables (binfo, base_class,
968 : vtbl_ptr_array);
969 : }
970 : }
971 : }
972 : }
973 8 : 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 8 : 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 8 : if (vtbl_ptr_array->length() > 0)
988 : {
989 : unsigned len = vtbl_ptr_array->length();
990 4 : while ((size_t) len > size_hint)
991 0 : size_hint <<= 1;
992 : }
993 8 : size_hint_arg = build_int_cst (size_type_node, size_hint);
994 :
995 : /* Get the key-buffer argument. */
996 8 : arg2 = build_key_buffer_arg (base_ptr_var_decl);
997 :
998 8 : if (str2 == NULL_TREE)
999 0 : str2 = build_string_literal ("unknown");
1000 :
1001 8 : if (flag_vtv_debug)
1002 0 : output_set_info (current->class_info->class_type,
1003 : *vtbl_ptr_array);
1004 :
1005 8 : 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 8 : if (vtbl_ptr_array->length() > 0
1016 8 : || (current->is_used
1017 4 : || (current->registered->size() > 0)))
1018 : {
1019 8 : insert_call_to_register_pair (vtbl_ptr_array,
1020 : arg1, arg2, size_hint_arg, str1,
1021 : str2, body);
1022 8 : registered_at_least_one = true;
1023 : }
1024 : }
1025 :
1026 8 : if (flag_vtv_counts && current_set_size > 0)
1027 0 : write_out_current_set_data (base_class, current_set_size);
1028 :
1029 : }
1030 :
1031 8 : 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 12 : vtv_register_class_hierarchy_information (tree init_routine_body)
1125 : {
1126 12 : bool registered_something = false;
1127 :
1128 12 : init_functions ();
1129 :
1130 12 : if (num_vtable_map_nodes == 0)
1131 : return false;
1132 :
1133 : /* Add class hierarchy pairs to the vtable map data structure. */
1134 8 : registered_something = register_all_pairs (init_routine_body);
1135 :
1136 8 : 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 12 : vtv_generate_init_routine (void)
1149 : {
1150 12 : tree init_routine_body;
1151 12 : bool vtable_classes_found = false;
1152 :
1153 12 : 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 12 : init_routine_body = vtv_start_verification_constructor_init_function ();
1160 :
1161 12 : vtable_classes_found =
1162 12 : vtv_register_class_hierarchy_information (init_routine_body);
1163 :
1164 12 : if (vtable_classes_found)
1165 : {
1166 8 : tree vtv_fndecl =
1167 8 : vtv_finish_verification_constructor_init_function (init_routine_body);
1168 8 : TREE_STATIC (vtv_fndecl) = 1;
1169 8 : TREE_USED (vtv_fndecl) = 1;
1170 8 : DECL_PRESERVE_P (vtv_fndecl) = 1;
1171 : /* We are running too late to generate any meaningful debug information
1172 : for this routine. */
1173 8 : DECL_IGNORED_P (vtv_fndecl) = 1;
1174 8 : if (flag_vtable_verify == VTV_PREINIT_PRIORITY && !TARGET_PECOFF)
1175 4 : DECL_STATIC_CONSTRUCTOR (vtv_fndecl) = 0;
1176 :
1177 8 : gimplify_function_tree (vtv_fndecl);
1178 8 : cgraph_node::add_new_function (vtv_fndecl, false);
1179 :
1180 8 : if (flag_vtable_verify == VTV_PREINIT_PRIORITY && !TARGET_PECOFF)
1181 : {
1182 4 : tree vtv_var
1183 4 : = build_decl (BUILTINS_LOCATION, VAR_DECL,
1184 : get_identifier ("__vtv_preinit"),
1185 4 : build_pointer_type (TREE_TYPE (vtv_fndecl)));
1186 4 : TREE_STATIC (vtv_var) = 1;
1187 4 : DECL_ARTIFICIAL (vtv_var) = 1;
1188 4 : DECL_INITIAL (vtv_var) = build_fold_addr_expr (vtv_fndecl);
1189 4 : set_decl_section_name (vtv_var, ".preinit_array");
1190 :
1191 4 : varpool_node::add (vtv_var);
1192 : }
1193 : }
1194 12 : pop_lang_context ();
1195 12 : }
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 24 : vtable_find_or_create_map_decl (tree base_type)
1206 : {
1207 24 : char *var_name = NULL;
1208 24 : struct vtbl_map_node *vtable_map_node = NULL;
1209 :
1210 : /* Verify the type has an associated vtable. */
1211 24 : if (!TYPE_BINFO (base_type) || !BINFO_VTABLE (TYPE_BINFO (base_type)))
1212 : return NULL;
1213 :
1214 : /* Create map lookup symbol for base class */
1215 8 : var_name = get_mangled_vtable_map_var_name (base_type);
1216 :
1217 : /* We've already created the variable; just look it. */
1218 8 : vtable_map_node = vtbl_map_get_node (TYPE_MAIN_VARIANT (base_type));
1219 :
1220 8 : 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 8 : tree var_decl = NULL;
1227 8 : tree var_type = build_pointer_type (void_type_node);
1228 8 : tree initial_value = integer_zero_node;
1229 :
1230 8 : var_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
1231 : get_identifier (var_name), var_type);
1232 :
1233 8 : DECL_EXTERNAL (var_decl) = 0;
1234 8 : TREE_STATIC (var_decl) = 1;
1235 8 : DECL_VISIBILITY (var_decl) = VISIBILITY_HIDDEN;
1236 8 : SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (var_name));
1237 8 : 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 8 : TREE_READONLY (var_decl) = 0;
1241 8 : DECL_IGNORED_P (var_decl) = 1;
1242 8 : 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 8 : set_decl_section_name (var_decl, ".vtable_map_vars");
1248 8 : symtab_node::get (var_decl)->implicit_section = true;
1249 8 : DECL_INITIAL (var_decl) = initial_value;
1250 :
1251 8 : comdat_linkage (var_decl);
1252 :
1253 8 : varpool_node::finalize_decl (var_decl);
1254 8 : if (!vtable_map_node)
1255 8 : vtable_map_node =
1256 8 : find_or_create_vtbl_map_node (TYPE_MAIN_VARIANT (base_type));
1257 8 : if (vtable_map_node->vtbl_map_decl == NULL_TREE)
1258 8 : vtable_map_node->vtbl_map_decl = var_decl;
1259 : }
1260 :
1261 8 : 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 16 : vtv_insert_single_class_info (tree type)
1271 : {
1272 16 : if (flag_vtable_verify)
1273 : {
1274 16 : tree binfo = TYPE_BINFO (type);
1275 16 : tree base_binfo;
1276 16 : struct vtbl_map_node *own_map;
1277 16 : int i;
1278 :
1279 : /* First make sure to create the map for this record type. */
1280 16 : own_map = vtable_find_or_create_map_decl (type);
1281 16 : if (own_map == NULL)
1282 16 : 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 16 : for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
1290 : {
1291 8 : tree tree_val = BINFO_TYPE (base_binfo);
1292 8 : struct vtbl_map_node *vtable_map_node = NULL;
1293 :
1294 8 : vtable_map_node = vtable_find_or_create_map_decl (tree_val);
1295 :
1296 8 : 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 16 : vtv_save_class_info (tree record)
1308 : {
1309 16 : if (!flag_vtable_verify || TREE_CODE (record) == UNION_TYPE)
1310 : return;
1311 :
1312 16 : if (!vlt_saved_class_info)
1313 8 : vec_alloc (vlt_saved_class_info, 10);
1314 :
1315 16 : gcc_assert (TREE_CODE (record) == RECORD_TYPE);
1316 :
1317 16 : 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 12 : vtv_recover_class_info (void)
1327 : {
1328 12 : tree current_class;
1329 12 : unsigned i;
1330 :
1331 12 : if (vlt_saved_class_info)
1332 : {
1333 24 : for (i = 0; i < vlt_saved_class_info->length(); ++i)
1334 : {
1335 16 : current_class = (*vlt_saved_class_info)[i];
1336 16 : gcc_assert (TREE_CODE (current_class) == RECORD_TYPE);
1337 16 : vtv_insert_single_class_info (current_class);
1338 : }
1339 : }
1340 12 : }
1341 :
1342 : #include "gt-cp-vtable-class-hierarchy.h"
|