public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: [PATCH] Vtable pointer verification, C++ front end changes (patch 1 of 3)
       [not found] <CABtf2+ROV47=LoN7v2=R9ef7WVpwZVhtax6TLUu4vrQ-R0Ci-A@mail.gmail.com>
@ 2013-01-30 17:44 ` Jason Merrill
  2013-02-01  0:25   ` Caroline Tice
  0 siblings, 1 reply; 4+ messages in thread
From: Jason Merrill @ 2013-01-30 17:44 UTC (permalink / raw)
  To: Caroline Tice
  Cc: GCC Patches, Luis Lozano, Diego Novillo, Bhaskar Janakiraman

I'm also touching on the middle-end and library changes, but would 
appreciate a more thorough review from others in those areas.

On 01/23/2013 05:25 PM, Caroline Tice wrote:
> Index: gcc/cp/g++spec.c

Changes to g++spec.c only affect the g++ driver, not the gcc driver. Are 
you sure this is what you want?  Can't you handle this stuff directly in 
the specs like address sanitizer does?

> @@ -17954,6 +17954,10 @@ mark_class_instantiated (tree t, int ext
>    if (! extern_p)
>      {
>        CLASSTYPE_DEBUG_REQUESTED (t) = 1;
> +
> +      if (flag_vtable_verify)
> +        vtv_save_class_info (t);

Why do you need this here as well as in finish_struct_1?

> -static tree
> +tree
>  get_mangled_id (tree decl)

It doesn't look like you call get_mangled_id anywhere, so I think you 
don't need this change anymore.

>    finalize_compilation_unit ();
>
> +  if (flag_vtable_verify)
> +    {
> +      /* Generate the special constructor initialization function that
> +         calls __VLTRegisterPairs, and give it a very high initialization
> +         priority.  */
> +      vtv_generate_init_routine ();
> +    }

Why do you want to do this after cgraph finalization?  Is it so that you 
know which vtables are really being emitted?  Please explain in the comment.

> +      if (flag_vtable_verify
> +          && strstr (IDENTIFIER_POINTER (DECL_NAME (fn)), ".vtable"))
> +        return fn;

How would this function end up with .vtable at the end of its name?

> +  if (TREE_CHAIN (base_class))
> +    class_type_decl = TREE_CHAIN (base_class);
> +  else
> +    class_type_decl = TYPE_NAME (base_class);
> +
> +  /* Temporarily remove any qualifiers on type.  */
> +  type_decl_type = TREE_TYPE (class_type_decl);
> +  save_quals = TYPE_QUALS (type_decl_type);
> +  reset_type_qualifiers (null_quals, type_decl_type);
> +
> +  base_id = DECL_ASSEMBLER_NAME (TREE_CHAIN (base_class));

I think you want TYPE_LINKAGE_IDENTIFIER here.

I don't understand what the qualifier business is trying to accomplish, 
especially since you never use type_decl_type.  You do this in several 
places, but it should never be necessary; classes don't have any 
qualifiers.

> +  if (vtbl_map_node_registration_find (base_vtable_map_node, vtable_decl,
> +                                       offset))
> +    return true;
> +
> +  vtbl_map_node_registration_insert (base_vtable_map_node, vtable_decl,
> +                                    offset);

Here you're doing two hash table lookups when one would be enough.

> +  vtbl_var_decl = get_vtbl_decl_for_binfo (TYPE_BINFO (record_type));

Here you could use CLASSTYPE_VTABLES (record_type).

> +      /* Check to see if we have found a constructor vtable.  Add its
> +         data if appropriate.  */

_ZTT indicates a VTT (vtable table, 
http://mentorembedded.github.com/cxx-abi/abi.html#vtable-ctor), which 
points to construction vtables, but is not itself a construction vtable.

In register_vptr_fields it seems that given a base B and derived D, you 
are adding all the elements of D's VTT to the list of valid vtables for 
a B, but this isn't correct; elements of D's VTT may be vtables for 
other bases, or other VTTs.   I think this might even miss some 
potential B vtables by not walking into sub-VTTs.

Since this function is just trying to register construction vtables, I 
think calling it "register_construction_vtables" would be clearer.

> +          && (strncmp (IDENTIFIER_POINTER (DECL_NAME (ztt_decl)),
> +                       "_ZTT", 4) == 0))

I think relying on the mangled name like this is going to be fragile; 
for instance, some targets use two underscores at the beginning of the 
mangled name.  Probably better to assume that if CLASSTYPE_VBASECLASSES 
(record_type), it's the VTT; that's what build_special_member_call does. 
  Or better yet, encapsulate that logic in a get_vtt function.

> +                      && TREE_CODE (TREE_OPERAND (val_vtbl_decl, 0))
> +                                                                   == VAR_DECL)

Odd indentation.

> +                  len1 = strlen (IDENTIFIER_POINTER
> +				     (DECL_NAME
> +				          (TREE_OPERAND
> +					     (base_class_decl_arg, 0))));
> +                  len2 = strlen (IDENTIFIER_POINTER
> +				     (DECL_NAME (val_vtbl_decl)));
> +                  arg1 = build_string_literal (len1 + 1,
> +                                               IDENTIFIER_POINTER
> +					        (DECL_NAME
> +						 (TREE_OPERAND
> +						  (base_class_decl_arg, 0))));
> +                  arg2 = build_string_literal (len2 + 1,
> +                                               IDENTIFIER_POINTER
> +					        (DECL_NAME (val_vtbl_decl)));

Since these are only used when debugging, let's only initialize them 
when debugging, too.  And instead of strlen (IDENTIFIER_POINTER, use 
IDENTIFIER_LENGTH.

> 2).  A linked list of all
> +   vtbl_map_nodes ("vtbl_map_nodes") for easy iteration through all of
> +   them; and 3). An array of vtbl_map_nodes, where the array index
> +   corresponds to the unique id of the vtbl_map_node, which gives us
> +   an easy way to use bitmaps to represent and find the vtable map
> +   nodes.

What's hard about iteration over an array?  FOR_EACH_VEC_ELT is pretty 
simple to use.  Is there another reason the list is desirable?

For that matter, you don't need the array, either; you can just use 
TYPE_UID for a bitmap key and use htab_traverse to iterate over all 
elements.

> +register_other_binfo_vtables (tree binfo, tree body, tree arg1, tree str1,

It seems like this function is saying that it's OK for the BINFO vptr to 
point to the vtable for one of its bases, but it really isn't except for 
a primary base, which ought to be handled by the normal process.

> +guess_num_vtable_pointers (struct vtv_graph_node *class_node)

I would think it would be better to pass the unrounded count to the 
library, and let the library decide how to adjust that number for 
allocation.

> +  /* Check array size, and re-size it if necessary.  */
...
> +      node->offsets = (unsigned *) xmalloc (10 * sizeof (unsigned));

Why not use VEC for your arrays?

> +void __VLTunprotect (void) __attribute__ ((constructor(98)));
> +void __VLTprotect (void) __attribute__ ((constructor(100)));
> +
> +void
> +__VLTunprotect (void)
> +{
> +  __VLTChangePermission (__VLTP_READ_WRITE);
> +}
> +
> +void
> +__VLTprotect (void)
> +{
> +  __VLTChangePermission (__VLTP_READ_ONLY);
> +}

You can add the attribute to the definitions by putting it before the 
return type.

> +  /* TODO: Temp fix. Needs to be tightened.  */
> +  if (num_vtable_map_nodes == 0)
> +    return false;;

TODO?

> +  var_name = ACONCAT (("_ZN4_VTVI", IDENTIFIER_POINTER (base_id),
> +                       "E12__vtable_mapE", NULL));

Please use the mangle.c machinery to generate mangled names.  And add 
demangling support to libiberty/cp-demangle.c.

> +/* Be careful about changing this routine. The values generated will
> +   be stored in the calls to InitSet. So, changing this routine may
> +   cause a binary incompatibility.  */

Making a particular hash function part of the ABI seems fragile.

> +      /* We cannot mark this variable as read-only otherwise the gold
> +         linker will not put it in the relro section. It seems if it
> +         is marked as read-only, gold will put it in the .text
> +         segment.  */

Well, yes; since you're going to be initializing it at run-time, it 
isn't read-only.  Same thing as with C++ const variables that need 
dynamic initialization.

> +  /* Let the garbabe collector collect the memory associated with the

"garbage"

> +void
> +vtv_save_class_info (tree record)
> +{
> +  if (!flag_vtable_verify || TREE_CODE (record) == UNION_TYPE)
> +    return;
> +
> +  gcc_assert (TREE_CODE (record) == RECORD_TYPE);
> +
> +  vlt_saved_class_info = tree_cons (NULL_TREE, record, vlt_saved_class_info);
> +}

This should really be an VEC, not a list.

> +find_and_remove_next_leaf_node (struct work_node **worklist)

This needs to free removed work nodes.

> +      if (! (DECL_NAME (TREE_OPERAND (rhs, 1)))
> +          || (strncmp (IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (rhs, 1))),
> +                       "_vptr.", 6) != 0))

You can use DECL_VIRTUAL_P to recognize the vptr FIELD_DECL.

> +type_name_is_vtable_pointer (tree lhs)

And then you shouldn't need to check this at all.

> +  ld = ggc_alloc_cleared_lang_decl (sizeof (struct lang_decl_fn));

lang_decl_fn is from the C++ front end, but you're not in the front end 
here.  It's probably simpler to use extern "C" for the library functions 
like we do for other bits of libsupc++.

> +reset_type_qualifiers (unsigned int new_quals, tree type_node)

This function is not safe and should be removed; as mentioned above, it 
shouldn't be needed anyway.

> +my_get_vtbl_decl_for_binfo (tree binfo)

You just copied get_vtbl_decl_for_binfo into the middle end.  And the 
two uses seem unnecessary: the first one seems redundant after checking 
BINFO_VTABLE, and the second one seems redundant with getting the vtable 
out of vtable_map_node.

> +              /* Find the previousg statement that gets the "_vptr"

"previous"

> +find_and_replace_var (gimple stmt, tree old_var, tree new_var)
> +find_stmt_in_bb_stmts (gimple stmt, gimple_stmt_iterator *gsi_temp)

These seem like generally useful functions that should live somewhere else.

> +                  if (POINTER_TYPE_P (TREE_TYPE (vtbl)))
> +                    force_gimple_operand (vtbl, &pre_p, 1, NULL);

You aren't doing anything with the return value here.  And it looks like 
the vtbl variable is unused anyway.

> -      switch_to_section (sect);
> +      if (sect->named.name
> +         && (strcmp (sect->named.name, ".vtable_map_vars") == 0))
> +       {
> +#if defined (OBJECT_FORMAT_ELF)
> +          targetm.asm_out.named_section (sect->named.name,
> +                                        sect->named.common.flags
> +                                        | SECTION_LINKONCE,
> +                                        DECL_NAME (decl));
> +          in_section = sect;
> +#else
> +          switch_to_section (sect);
> +#endif
> +        }
> +      else
> +        switch_to_section (sect);

> +  if (strcmp (name, ".vtable_map_vars") == 0)
> +      flags |= SECTION_LINKONCE;

These changes should not be necessary.  Just set DECL_ONE_ONLY on the 
vtable map variables.

> +       vtv_rts.cc \
> +       vtv_malloc.cc \
> +       vtv_utils.cc

It seems to me that this code belongs in a separate library like 
libsanitizer, not in libstdc++.

> +++ b/libstdc++-v3/libsupc++/vtv_map.h

Do you really need yet another hash table?

Jason

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Vtable pointer verification, C++ front end changes (patch 1 of 3)
  2013-01-30 17:44 ` [PATCH] Vtable pointer verification, C++ front end changes (patch 1 of 3) Jason Merrill
@ 2013-02-01  0:25   ` Caroline Tice
  2013-02-01 16:49     ` Jason Merrill
  0 siblings, 1 reply; 4+ messages in thread
From: Caroline Tice @ 2013-02-01  0:25 UTC (permalink / raw)
  To: Jason Merrill
  Cc: GCC Patches, Luis Lozano, Diego Novillo, Bhaskar Janakiraman

On Wed, Jan 30, 2013 at 9:26 AM, Jason Merrill <jason@redhat.com> wrote:
> I'm also touching on the middle-end and library changes, but would
> appreciate a more thorough review from others in those areas.
>
> On 01/23/2013 05:25 PM, Caroline Tice wrote:
>>
>> Index: gcc/cp/g++spec.c
>
>
> Changes to g++spec.c only affect the g++ driver, not the gcc driver. Are you
> sure this is what you want?  Can't you handle this stuff directly in the
> specs like address sanitizer does?
>
>> @@ -17954,6 +17954,10 @@ mark_class_instantiated (tree t, int ext
>>    if (! extern_p)
>>      {
>>        CLASSTYPE_DEBUG_REQUESTED (t) = 1;
>> +
>> +      if (flag_vtable_verify)
>> +        vtv_save_class_info (t);
>
> Why do you need this here as well as in finish_struct_1?
>

If we don't have this in both places, then we miss getting vtable
pointers for instantiated templates.


>> -static tree
>> +tree
>>  get_mangled_id (tree decl)
>
>
> It doesn't look like you call get_mangled_id anywhere, so I think you don't
> need this change anymore.

You are right; this is leftover from an earlier version where we were
calling this function directly; I'll remove the change.

>
>>    finalize_compilation_unit ();
>>
>> +  if (flag_vtable_verify)
>> +    {
>> +      /* Generate the special constructor initialization function that
>> +         calls __VLTRegisterPairs, and give it a very high initialization
>> +         priority.  */
>> +      vtv_generate_init_routine ();
>> +    }
>
>
> Why do you want to do this after cgraph finalization?  Is it so that you
> know which vtables are really being emitted?  Please explain in the comment.

Exactly.  We need to know which vtables are really emitted before we
output __VLTRegisterPair calls; otherwise we got in trouble emitting
calls for vtables that weren't output, or causing vtables to be output
when otherwise they wouldn't be.

>
>> +      if (flag_vtable_verify
>> +          && strstr (IDENTIFIER_POINTER (DECL_NAME (fn)), ".vtable"))
>> +        return fn;
>
>
> How would this function end up with .vtable at the end of its name?
>

Whoops.  This is leftover from older code when we modified
start_objects and added that to the constructor initialization
function. I will change this.


>> +  if (TREE_CHAIN (base_class))
>> +    class_type_decl = TREE_CHAIN (base_class);
>> +  else
>> +    class_type_decl = TYPE_NAME (base_class);
>> +
>> +  /* Temporarily remove any qualifiers on type.  */
>> +  type_decl_type = TREE_TYPE (class_type_decl);
>> +  save_quals = TYPE_QUALS (type_decl_type);
>> +  reset_type_qualifiers (null_quals, type_decl_type);
>> +
>> +  base_id = DECL_ASSEMBLER_NAME (TREE_CHAIN (base_class));
>
>
> I think you want TYPE_LINKAGE_IDENTIFIER here.
>

I don't know the difference between DECL_ASSEMBLER_NAME and
TYPE_LINKAGE_IDENTIFIER.  We are just trying to get the mangled name
for the class.

> I don't understand what the qualifier business is trying to accomplish,
> especially since you never use type_decl_type.  You do this in several
> places, but it should never be necessary; classes don't have any qualifiers.
>

We used to not have the "qualifier business", assuming that classes
did not have any type qualifiers.  This turned out not to be a true
assumption.  Occasionally we were getting a case where a class had a
"const" qualifier attached to it *sometimes*.  We used the mangled
name to look it up in our hashtable, and it didn't find the entry for
the class (which had been put in without the const qualifier).  So we
temporarily remove any type qualifiers before getting the mangled
name; then re-apply whatever qualifiers were there before.  The cod
actually works because the type_decl_type we change the qualifiers on
is a subtree of the class_type_decl, which is a subtree of the
base_class that we get the mangled name from. (We have tested this
code; it works and fixes our problem).

>> +  if (vtbl_map_node_registration_find (base_vtable_map_node, vtable_decl,
>> +                                       offset))
>> +    return true;
>> +
>> +  vtbl_map_node_registration_insert (base_vtable_map_node, vtable_decl,
>> +                                    offset);
>
>
> Here you're doing two hash table lookups when one would be enough.
>

As written the insert function doesn't return anything to let you know
whether the item was already there or not, which we need to know (we
use the results here to avoid generating redundant calls to
__VLTRegisterPair.  I suppose we could modify the insert function to
return a boolean indicating if the item was already in the hashtable,
and then we could get by with just one call here...



>
>> 2).  A linked list of all
>> +   vtbl_map_nodes ("vtbl_map_nodes") for easy iteration through all of
>> +   them; and 3). An array of vtbl_map_nodes, where the array index
>> +   corresponds to the unique id of the vtbl_map_node, which gives us
>> +   an easy way to use bitmaps to represent and find the vtable map
>> +   nodes.
>
>
> What's hard about iteration over an array?  FOR_EACH_VEC_ELT is pretty
> simple to use.  Is there another reason the list is desirable?
>
I suppose we could eliminate the linked list...

> For that matter, you don't need the array, either; you can just use TYPE_UID
> for a bitmap key and use htab_traverse to iterate over all elements.
>

I don't understand how this would work.  I think we need the vec, at
least, to have direct access based on TYPE_UID (which is also the vec
index).


>
>> +guess_num_vtable_pointers (struct vtv_graph_node *class_node)
>
>
> I would think it would be better to pass the unrounded count to the library,
> and let the library decide how to adjust that number for allocation.

If there is any computation we can do at compile-time rather than
run-time, we would rather do it at compile time.

>
>> +  /* Check array size, and re-size it if necessary.  */
>
> ...
>>
>> +      node->offsets = (unsigned *) xmalloc (10 * sizeof (unsigned));
>
>
> Why not use VEC for your arrays?
>

Will do.

>> +  var_name = ACONCAT (("_ZN4_VTVI", IDENTIFIER_POINTER (base_id),
>> +                       "E12__vtable_mapE", NULL));
>
>
> Please use the mangle.c machinery to generate mangled names.  And add
> demangling support to libiberty/cp-demangle.c.
>

I don't think the mangle.c machinery can generate the mangled name
that we need.  We did construct this mangled name for our vtable map
variables very carefully, so that it does actually demangle properly,
with no additional support needed.

For example, one of the vtable map variable names generated by the
code above is:

_ZN4_VTVISt13bad_exceptionE12__vtable_mapE

$ c++filt _ZN4_VTVISt13bad_exceptionE12__vtable_mapE
_VTV<std::bad_exception>::__vtable_map
$

Is this really not OK?

>> +/* Be careful about changing this routine. The values generated will
>> +   be stored in the calls to InitSet. So, changing this routine may
>> +   cause a binary incompatibility.  */
>
>
> Making a particular hash function part of the ABI seems fragile.
>

Again, while I understand your concern, we are VERY concerned about
runtime performance, and we want to push any computations that we can
to compile-time.

>> +reset_type_qualifiers (unsigned int new_quals, tree type_node)
>
>
> This function is not safe and should be removed; as mentioned above, it
> shouldn't be needed anyway.
>

As I explained above, we originally didn't have it and then found we
really needed it.   If you know of a safer or better way to accomplish
the same thing we would be happy to hear about it.

>> -      switch_to_section (sect);
>> +      if (sect->named.name
>> +         && (strcmp (sect->named.name, ".vtable_map_vars") == 0))
>> +       {
>> +#if defined (OBJECT_FORMAT_ELF)
>> +          targetm.asm_out.named_section (sect->named.name,
>> +                                        sect->named.common.flags
>> +                                        | SECTION_LINKONCE,
>> +                                        DECL_NAME (decl));
>> +          in_section = sect;
>> +#else
>> +          switch_to_section (sect);
>> +#endif
>> +        }
>> +      else
>> +        switch_to_section (sect);
>
>
>> +  if (strcmp (name, ".vtable_map_vars") == 0)
>> +      flags |= SECTION_LINKONCE;
>
>
> These changes should not be necessary.  Just set DECL_ONE_ONLY on the vtable
> map variables.
>

I believe this change was necessary so that each vtable map variable
would have its own comdat name and be in its own comdat group...but I
will revisit this and see if we still need it.

>> +++ b/libstdc++-v3/libsupc++/vtv_map.h
>
>
> Do you really need yet another hash table?
>

Yes, sadly, we really do.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Vtable pointer verification, C++ front end changes (patch 1 of 3)
  2013-02-01  0:25   ` Caroline Tice
@ 2013-02-01 16:49     ` Jason Merrill
  0 siblings, 0 replies; 4+ messages in thread
From: Jason Merrill @ 2013-02-01 16:49 UTC (permalink / raw)
  To: Caroline Tice
  Cc: GCC Patches, Luis Lozano, Diego Novillo, Bhaskar Janakiraman

On 01/31/2013 07:24 PM, Caroline Tice wrote:
> On Wed, Jan 30, 2013 at 9:26 AM, Jason Merrill <jason@redhat.com> wrote:
>>> @@ -17954,6 +17954,10 @@ mark_class_instantiated (tree t, int ext
>>> +      if (flag_vtable_verify)
>>> +        vtv_save_class_info (t);
>>
>> Why do you need this here as well as in finish_struct_1?
>
> If we don't have this in both places, then we miss getting vtable
> pointers for instantiated templates.

Why?  instantiated templates also go through finish_struct_1.  And we 
only hit this function for explicit instantiations, not implicit.

>>> +  base_id = DECL_ASSEMBLER_NAME (TREE_CHAIN (base_class));
>>
>> I think you want TYPE_LINKAGE_IDENTIFIER here.
>
> I don't know the difference between DECL_ASSEMBLER_NAME and
> TYPE_LINKAGE_IDENTIFIER.  We are just trying to get the mangled name
> for the class.

Ah, I guess you don't want TYPE_LINKAGE_IDENTIFIER, as that's the simple 
name rather than the mangled one.  But for the external name you always 
want to look at TYPE_NAME, not TREE_CHAIN (which corresponds to 
TYPE_STUB_DECL); in the case of an anonymous class that gets a name for 
linkage purposes from a typedef, the latter will have the original 
placeholder name, while the former will have the name used in mangling.

>> I don't understand what the qualifier business is trying to accomplish,
>> especially since you never use type_decl_type.  You do this in several
>> places, but it should never be necessary; classes don't have any qualifiers.
>
> We used to not have the "qualifier business", assuming that classes
> did not have any type qualifiers.  This turned out not to be a true
> assumption.  Occasionally we were getting a case where a class had a
> "const" qualifier attached to it *sometimes*.

Why?  You are getting a qualified variant of the class somehow.  Where 
is it coming from?

>> Here you're doing two hash table lookups when one would be enough.
>
> As written the insert function doesn't return anything to let you know
> whether the item was already there or not, which we need to know (we
> use the results here to avoid generating redundant calls to
> __VLTRegisterPair.  I suppose we could modify the insert function to
> return a boolean indicating if the item was already in the hashtable,
> and then we could get by with just one call here...

Yep, that's what I was thinking.

>> For that matter, you don't need the array, either; you can just use TYPE_UID
>> for a bitmap key and use htab_traverse to iterate over all elements.
>
> I don't understand how this would work.  I think we need the vec, at
> least, to have direct access based on TYPE_UID (which is also the vec
> index).

TYPE_UID is already a property of the type, different from the class_uid 
in your patch.

But yes, I guess you do need some way to get from your index back to the 
type, so never mind.

>>> +guess_num_vtable_pointers (struct vtv_graph_node *class_node)
>>
>> I would think it would be better to pass the unrounded count to the library,
>> and let the library decide how to adjust that number for allocation.
>
> If there is any computation we can do at compile-time rather than
> run-time, we would rather do it at compile time.

I guess that makes sense.

>>> +  var_name = ACONCAT (("_ZN4_VTVI", IDENTIFIER_POINTER (base_id),
>>> +                       "E12__vtable_mapE", NULL));
>>
> $ c++filt _ZN4_VTVISt13bad_exceptionE12__vtable_mapE
> _VTV<std::bad_exception>::__vtable_map

Interesting.  Does this _VTV template appear anywhere else?

Even if we stay with this approach to producing the name, I'd like it to 
happen in a (new) function in mangle.c.

>>> +reset_type_qualifiers (unsigned int new_quals, tree type_node)
>>
>> This function is not safe and should be removed; as mentioned above, it
>> shouldn't be needed anyway.
>
> As I explained above, we originally didn't have it and then found we
> really needed it.   If you know of a safer or better way to accomplish
> the same thing we would be happy to hear about it.

TYPE_MAIN_VARIANT will give you an unqualified variant of any qualified 
type.

Jason

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Vtable pointer verification, C++ front end changes (patch 1 of 3)
@ 2013-01-23 22:35 Caroline Tice
  0 siblings, 0 replies; 4+ messages in thread
From: Caroline Tice @ 2013-01-23 22:35 UTC (permalink / raw)
  To: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 2547 bytes --]

I have made the requested changes to the previous patches I submitted
for the vtable verification feature. As requested, I have broken this
into three patches:  the C++ front end changes, the main gcc changes,
and the runtime library changes.  Here are the C++ front end changes
for the vtable verification feature.

-- Caroline Tice
cmtice@google.com

ChangeLog:

2013-01-23  Caroline Tice  <cmtice@google.com>

	* init.c (build_vtbl_address):  Make function not static (externally
	visible).
	* class.c (finish_struct_1):  Add call to vtv_save_class_info if vtable
	verification is turned on.
	* Make-lang.in: (CXX_AND_OBJCXX_OBJS):  Add vtable-class-hierarchy.o to
	list of object files.
	(vtable-class-hierarchy.o):  Add rule for building object file.
	* g++spec.c (VTABLE_LOAD_MODULE_UNIT): New macro for link option needed
	with vtable verification.
	(lang_specific_driver): Added variable to indicate if vtable
	verification option is used, and which flavor. Process -fvtable-verify
	option, update num_args if option is present, and add appropriate
	driver options if fvtable-verify is present.
	* pt.c (mark_class_instantiated):  Add call to vtv_save_class_info if
	vtable verification is turned on.
	* decl2.c (finish_objects):  Change the return type from void to tree;
	make it return the function decl is is working on.  Make it return
	early if the function is a vtable verification constructor init
	function.
	(cp_write_global_declarations):  If vtable verification is turned on,
	call vtv_recover_class_info and
	vtv_compute_class_hierarchy_transitive_closure before calling
	finalize_compilation_unit.  Call vtv_generate_init_routine after.
	(vtv_start_verification_constructor_init_function): New externally
	visible wrapper function to call start_objects for vtable verification.
	(vtv_finish_verification_constructor_init_functin):  New externally
	visible wrapper function to call finish_objects for vtable
	verification.
	* config-lang.in: Add vtable-class-hierarchy.c to the list of files
	that use GCC's garbage collector.
	* vtable-class-hierarchy.c:  New file, containing the bulk of vtable
	verification's front-end work.
	* mangle.c (get_mangled_id): Make the function not static (externally
	visible).
	* cp-tree.h: Add extern function declaratins for
	vtv_start_verification_constructor_init_function,
	vtv_finish_verification_constructor_init_function, build_vtbl_address,
	vtv_compute_class_hierarchy_transitive_closure,
	vtv_generate_init_routine, vtv_save_class_info,
	vtv_recover_class_info and get_mangled_id.

[-- Attachment #2: fsf-vtable-verification.v4.c++front-end.patch --]
[-- Type: application/octet-stream, Size: 64224 bytes --]

Index: gcc/cp/init.c
===================================================================
--- gcc/cp/init.c	(revision 195313)
+++ gcc/cp/init.c	(working copy)
@@ -43,7 +43,6 @@ static tree initializing_context (tree);
 static void expand_cleanup_for_base (tree, tree);
 static tree dfs_initialize_vtbl_ptrs (tree, void *);
 static tree build_field_list (tree, tree, int *);
-static tree build_vtbl_address (tree);
 static int diagnose_uninitialized_cst_or_ref_member_1 (tree, tree, bool, bool);
 
 /* We are about to generate some complex initialization code.
@@ -1105,7 +1104,7 @@ emit_mem_initializers (tree mem_inits)
 /* Returns the address of the vtable (i.e., the value that should be
    assigned to the vptr) for BINFO.  */
 
-static tree
+tree
 build_vtbl_address (tree binfo)
 {
   tree binfo_for = binfo;
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c	(revision 195313)
+++ gcc/cp/class.c	(working copy)
@@ -6381,6 +6381,9 @@ finish_struct_1 (tree t)
 
   maybe_suppress_debug_info (t);
 
+  if (flag_vtable_verify)
+    vtv_save_class_info (t);
+
   dump_class_hierarchy (t);
 
   /* Finish debugging output for this type.  */
Index: gcc/cp/Make-lang.in
===================================================================
--- gcc/cp/Make-lang.in	(revision 195313)
+++ gcc/cp/Make-lang.in	(working copy)
@@ -80,7 +80,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.
  cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
  cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \
  cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
- cp/cp-gimplify.o $(CXX_C_OBJS)
+ cp/cp-gimplify.o cp/vtable-class-hierarchy.o $(CXX_C_OBJS)
 
 # Language-specific object files for C++.
 CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
@@ -338,7 +338,12 @@ cp/parser.o: cp/parser.c $(CXX_TREE_H) $
   c-family/c-objc.h tree-pretty-print.h $(CXX_PARSER_H) $(TIMEVAR_H)
 cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) $(C_COMMON_H) \
 	$(TM_H) coretypes.h pointer-set.h tree-iterator.h $(SPLAY_TREE_H)
-
+cp/vtable-class-hierarchy.o: cp/vtable-class-hierarchy.c \
+  $(TM_H) $(TIMEVAR_H) $(CXX_TREE_H) intl.h $(CXX_PARSER_H) cp/decl.h \
+  $(FLAGS_H) $(DIAGNOSTIC_CORE_H) output.h $(CGRAPH_H) c-family/c-common.h \
+  c-family/c-objc.h $(PLUGIN_H) \
+  tree-iterator.h tree-vtable-verify.h $(GIMPLE_H) \
+  gt-cp-vtable-class-hierarchy.h
 cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
 	$(TM_H) $(CXX_TREE_H) $(TIMEVAR_H) gt-cp-name-lookup.h $(PARAMS_H) \
 	$(DIAGNOSTIC_CORE_H) $(FLAGS_H) debug.h pointer-set.h
Index: gcc/cp/g++spec.c
===================================================================
--- gcc/cp/g++spec.c	(revision 195313)
+++ gcc/cp/g++spec.c	(working copy)
@@ -50,6 +50,11 @@ along with GCC; see the file COPYING3.  
 #define LIBSTDCXX_STATIC NULL
 #endif
 
+/* Link command for linking in libvtv_inint when doing 'std' vtable
+   verification.  */
+
+#define VTABLE_LOAD_MODULE_INIT "--whole-archive,-lvtv_init,--no-whole-archive"
+
 void
 lang_specific_driver (struct cl_decoded_option **in_decoded_options,
 		      unsigned int *in_decoded_options_count,
@@ -111,6 +116,11 @@ lang_specific_driver (struct cl_decoded_
   /* The total number of arguments with the new stuff.  */
   unsigned int num_args = 1;
 
+  /* The command line contains a -fvtable_verify. We need to add the
+     init library if we are linking and if we are adding the stdc++
+     library.  */
+  int saw_vtable_verify = 0;
+
   argc = *in_decoded_options_count;
   decoded_options = *in_decoded_options;
   added_libraries = *in_added_libraries;
@@ -236,6 +246,14 @@ lang_specific_driver (struct cl_decoded_
 	      }
 	  }
 	  break;
+
+        case OPT_fvtable_verify_:
+          if (strcmp (arg, "std") == 0)
+            saw_vtable_verify = 1;
+          else if (strcmp (arg, "preinit") == 0)
+            saw_vtable_verify = 2;
+          break;
+
 	}
     }
 
@@ -247,6 +265,12 @@ lang_specific_driver (struct cl_decoded_
 
   /* Add one for shared_libgcc or extra static library.  */
   num_args = argc + added + need_math + (library > 0) * 4 + 1;
+
+  /* Add two more linker args, '-Wl,-u_vtable_map_vars_start and
+     '-Wl,-u_vtable_map_vars_end.  */
+  if (saw_vtable_verify)
+    num_args += 2;
+
   new_decoded_options = XNEWVEC (struct cl_decoded_option, num_args);
 
   i = 0;
@@ -309,6 +333,33 @@ lang_specific_driver (struct cl_decoded_
       j++;
     }
 
+  /* Add option to make sure that if we are doing 'std' vtable
+     verification then we link with the libvtv_init library.  */
+
+  if (saw_vtable_verify == 1 && library > 0)
+    {
+      generate_option(OPT_Wl_, VTABLE_LOAD_MODULE_INIT, 1,
+                      CL_DRIVER, &new_decoded_options[j]);
+      added_libraries++;
+      j++;
+    }
+
+  /* If we are doing vtable verification, make sure the linker does
+     not garbage-collect the special symbols that mark the start and
+     end of the ".vtable_map_vars" section in the binary.  (See
+     comments in vtv_start.c and vtv_end.c for more details).  */
+
+  if (saw_vtable_verify > 0)
+    {
+      generate_option (OPT_Wl_,"-u_vtable_map_vars_start", 1,
+                       CL_DRIVER, &new_decoded_options[j]);
+      j++;
+
+      generate_option (OPT_Wl_,"-u_vtable_map_vars_end", 1,
+                       CL_DRIVER, &new_decoded_options[j]);
+      j++;
+    }
+
   /* Add `-lstdc++' if we haven't already done so.  */
   if (library > 0)
     {
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 195313)
+++ gcc/cp/pt.c	(working copy)
@@ -17954,6 +17954,10 @@ mark_class_instantiated (tree t, int ext
   if (! extern_p)
     {
       CLASSTYPE_DEBUG_REQUESTED (t) = 1;
+
+      if (flag_vtable_verify)
+        vtv_save_class_info (t);
+
       rest_of_type_compilation (t, 1);
     }
 }
Index: gcc/cp/decl2.c
===================================================================
--- gcc/cp/decl2.c	(revision 195313)
+++ gcc/cp/decl2.c	(working copy)
@@ -68,7 +68,7 @@ static void mark_vtable_entries (tree);
 static bool maybe_emit_vtables (tree);
 static bool acceptable_java_type (tree);
 static tree start_objects (int, int);
-static void finish_objects (int, int, tree);
+static tree finish_objects (int, int, tree);
 static tree start_static_storage_duration_function (unsigned);
 static void finish_static_storage_duration_function (tree);
 static priority_info get_priority_info (int);
@@ -3000,7 +3000,8 @@ generate_tls_wrapper (tree fn)
 }
 
 /* Start the process of running a particular set of global constructors
-   or destructors.  Subroutine of do_[cd]tors.  */
+   or destructors.  Subroutine of do_[cd]tors.  Also called from
+   vtv_start_verification_constructor_init_function.  */
 
 static tree
 start_objects (int method_type, int initp)
@@ -3053,9 +3054,13 @@ start_objects (int method_type, int init
 }
 
 /* Finish the process of running a particular set of global constructors
-   or destructors.  Subroutine of do_[cd]tors.  */
+   or destructors.  Subroutine of do_[cd]tors.  Also called from
+   vtv_finish_verification_constructor_init_function.
 
-static void
+   This function returns a tree containing the function decl for the function
+   it finished creating.  */
+
+static tree
 finish_objects (int method_type, int initp, tree body)
 {
   tree fn;
@@ -3068,6 +3073,10 @@ finish_objects (int method_type, int ini
     {
       DECL_STATIC_CONSTRUCTOR (fn) = 1;
       decl_init_priority_insert (fn, initp);
+
+      if (flag_vtable_verify
+          && strstr (IDENTIFIER_POINTER (DECL_NAME (fn)), ".vtable"))
+        return fn;
     }
   else
     {
@@ -3076,6 +3085,7 @@ finish_objects (int method_type, int ini
     }
 
   expand_or_defer_fn (fn);
+  return fn;
 }
 
 /* The names of the parameters to the function created to handle
@@ -4315,8 +4325,22 @@ cp_write_global_declarations (void)
   timevar_stop (TV_PHASE_DEFERRED);
   timevar_start (TV_PHASE_OPT_GEN);
 
+  if (flag_vtable_verify)
+    {
+      vtv_recover_class_info ();
+      vtv_compute_class_hierarchy_transitive_closure ();
+    }
+
   finalize_compilation_unit ();
 
+  if (flag_vtable_verify)
+    {
+      /* Generate the special constructor initialization function that
+         calls __VLTRegisterPairs, and give it a very high initialization
+         priority.  */
+      vtv_generate_init_routine ();
+    }
+
   timevar_stop (TV_PHASE_OPT_GEN);
   timevar_start (TV_PHASE_CHECK_DBGINFO);
 
@@ -4687,4 +4711,16 @@ mark_used (tree decl)
   return true;
 }
 
+tree
+vtv_start_verification_constructor_init_function (void)
+{
+  return start_objects ('I', MAX_RESERVED_INIT_PRIORITY - 1);
+}
+
+tree
+vtv_finish_verification_constructor_init_function (tree function_body)
+{
+  return finish_objects ('I', MAX_RESERVED_INIT_PRIORITY - 1, function_body);
+}
+
 #include "gt-cp-decl2.h"
Index: gcc/cp/config-lang.in
===================================================================
--- gcc/cp/config-lang.in	(revision 195313)
+++ gcc/cp/config-lang.in	(working copy)
@@ -29,4 +29,4 @@ compilers="cc1plus\$(exeext)"
 
 target_libs="target-libstdc++-v3"
 
-gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c"
+gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c \$(srcdir)/cp/vtable-class-hierarchy.c"
Index: gcc/cp/vtable-class-hierarchy.c
===================================================================
--- gcc/cp/vtable-class-hierarchy.c	(revision 0)
+++ gcc/cp/vtable-class-hierarchy.c	(revision 0)
@@ -0,0 +1,1257 @@
+/* Copyright (C) 2012  Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* Virtual Table Pointer Security Pass - Detect corruption of vtable pointers
+   before using them for virtual method dispatches.  */
+
+/* This file is part of the vtable security feature implementation.
+   The vtable security feature is designed to detect when a virtual
+   call is about to be made through an invalid vtable pointer
+   (possibly due to data corruption or malicious attacks). The
+   compiler finds every virtual call, and inserts a verification call
+   before the virtual call.  The verification call takes the actual
+   vtable pointer value in the object through which the virtual call
+   is being made, and compares the vtable pointer against a set of all
+   valid vtable pointers that the object could contain (this set is
+   based on the declared type of the object).  If the pointer is in
+   the valid set, execution is allowed to continue; otherwise the
+   program is halted.
+
+  There are several pieces needed in order to make this work: 1. For
+  every virtual class in the program (i.e. a class that contains
+  virtual methods), we need to build the set of all possible valid
+  vtables that an object of that class could point to.  This includes
+  vtables for any class(es) that inherit from the class under
+  consideration.  2. For every such data set we build up, we need a
+  way to find and reference the data set.  This is complicated by the
+  fact that the real vtable addresses are not known until runtime,
+  when the program is loaded into memory, but we need to reference the
+  sets at compile time when we are inserting verification calls into
+  the program.  3.  We need to find every virtual call in the program,
+  and insert the verification call (with the appropriate arguments)
+  before the virtual call.  4. We need some runtime library pieces:
+  the code to build up the data sets at runtime; the code to actually
+  perform the verification using the data sets; and some code to set
+  protections on the data sets, so they themselves do not become
+  hacker targets.
+
+  To find and reference the set of valid vtable pointers for any given
+  virtual class, we create a special global varible for each virtual
+  class.  We refer to this as the "vtable map variable" for that
+  class.  The vtable map variable has the type "void *", and is
+  initialized by the compiler to NULL.  At runtime when the set of
+  valid vtable pointers for a virtual class, e.g. class Foo, is built,
+  the vtable map variable for class Foo is made to point to the set.
+  During compile time, when the compiler is inserting verification
+  calls into the program, it passes the vtable map variable for the
+  appropriate class to the verification call, so that at runtime the
+  verification call can find the appropriate data set.
+
+  The actual set of valid vtable pointers for a virtual class,
+  e.g. class Foo, cannot be built until runtime, when the vtables get
+  loaded into memory and their addresses are known.  But the knowledge
+  about which vtables belong in which class' hierarchy is only known
+  at compile time.  Therefore at compile time we collect class
+  hierarchy and vtable information about every virtual class, and we
+  generate calls to build up the data sets at runtime.  To build the
+  data sets, we call one of the functions we add to the runtime
+  library, __VLTRegisterPair.  __VLTRegisterPair takes two arguments,
+  a vtable map variable and the address of a vtable.  If the vtable
+  map variable is currently NULL, it creates a new data set (hash
+  table), makes the vtable map variable point to the new data set, and
+  inserts the vtable address into the data set.  If the vtable map
+  variable is not NULL, it just inserts the vtable address into the
+  data set.  In order to make sure that our data sets are built before
+  any verification calls happen, we create a special constructor
+  initialization function for each compilation unit, give it a very
+  high initialization priority, and insert all of our calls to
+  __VLTRegisterPair into our special constructor initialization
+  function.
+
+  The vtable verification feature is controlled by the flag
+  '-fvtable-verify='.  There are three flavors of this:
+  '-fvtable-verify=std', '-fvtable-verify=preinit', and
+  '-fvtable-verify=none'.  If the option '-fvtable-verfy=preinit' is
+  used, then our constructor initialization function gets put into the
+  preinit array.  This is necessary if there are data sets that need
+  to be built very early in execution.  If the constructor
+  initialization function gets put into the preinit array, the we also
+  add calls to __VLTChangePermission at the beginning and end of the
+  function.  The call at the beginning sets the permissions on the
+  data sets and vtable map variables to read/write, and the one at the
+  end makes them read-only.  If the '-fvtable-verify=std' option is
+  used, the constructor initialization functions are executed at their
+  normal time, and the __VLTChangePermission calls are handled
+  differently (see the comments in libstdc++-v3/libsupc++/vtv_rts.cc).
+  The option '-fvtable-verify=none' turns off vtable verification.
+
+  This file contains code to find and record the class hierarchies for
+  the virtual classes in a program, and all the vtables associated
+  with each such class; to generate the vtable map variables; and to
+  generate the constructor initialization function (with the calls to
+  __VLTRegisterPair, and __VLTChangePermission).  The main data
+  structures used for collecting the class hierarchy data and
+  building/maintaining the vtable map variable data are defined in
+  gcc/tree-vtable-verify.h, because they are used both here and in
+  gcc/tree-vtable-verify.c.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "timevar.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "intl.h"
+#include "c-family/c-pragma.h"
+#include "decl.h"
+#include "flags.h"
+#include "diagnostic-core.h"
+#include "output.h"
+#include "target.h"
+#include "cgraph.h"
+#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
+#include "plugin.h"
+#include "tree-iterator.h"
+#include "tree-vtable-verify.h"
+#include "gimple.h"
+
+/* Mark these specially since they need to be stored in precompiled
+   header IR.  */
+static GTY (()) tree vlt_saved_class_info = NULL_TREE;
+static GTY (()) tree vlt_register_pairs_fndecl = NULL_TREE;
+static GTY (()) tree vlt_init_set_symbol_fndecl = NULL_TREE;
+static GTY (()) tree vlt_change_permission_fndecl = NULL_TREE;
+
+struct work_node {
+  struct vtv_graph_node *node;
+  struct work_node *next;
+};
+
+struct vtbl_map_node *vtable_find_or_create_map_decl (tree);
+
+/* As part of vtable verification the compiler generates and inserts calls
+   to __VLTRegisterPair and __VLTChangePermission, which are in libsupc++.
+   This function builds and initializes the function decls that are used
+   in generating those function calls.
+
+   In addition to __VLTRegisterPair there is also __VLTRegisterPairDebug
+   which can be used in place of __VLTRegisterPair, and which takes extra
+   parameters and outputs extra information, to help debug problems.  The
+   debug version of this function is generated and used if vtv_debug is true.
+
+   The signatures for these functions are:
+
+   void __VLTChangePermission (int);
+   void __VLTRegisterPair (void **, void*, int);
+   void __VLTRegisterPairDebug (void**, void *, int, char *, int, char *, int);
+*/
+
+static void
+init_functions (void)
+{
+  tree void_ptr_type = build_pointer_type (void_type_node);
+  tree arg_types = NULL_TREE;
+  tree change_permission_type = void_type_node;
+  tree register_pairs_type = void_type_node;
+  tree init_set_symbol_type = void_type_node;
+  tree const_char_ptr_type = build_pointer_type (build_qualified_type
+                                                           (char_type_node,
+                                                            TYPE_QUAL_CONST));
+
+  if (vlt_change_permission_fndecl != NULL_TREE)
+    return;
+
+  gcc_assert (vlt_register_pairs_fndecl == NULL_TREE);
+
+  arg_types = build_tree_list (NULL_TREE, integer_type_node);
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+  change_permission_type = build_function_type (change_permission_type,
+                                                arg_types);
+  vlt_change_permission_fndecl = build_fn_decl ("__VLTChangePermission",
+                                                change_permission_type);
+  TREE_NOTHROW (vlt_change_permission_fndecl) = 1;
+  DECL_ATTRIBUTES (vlt_change_permission_fndecl) =
+                    tree_cons (get_identifier ("leaf"), NULL,
+                               DECL_ATTRIBUTES (vlt_change_permission_fndecl));
+  TREE_PUBLIC (vlt_change_permission_fndecl) = 1;
+  DECL_PRESERVE_P (vlt_change_permission_fndecl) = 1;
+  retrofit_lang_decl (vlt_change_permission_fndecl);
+  SET_DECL_LANGUAGE (vlt_change_permission_fndecl, lang_cplusplus);
+
+  arg_types = build_tree_list (NULL_TREE, build_pointer_type (void_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   const_ptr_type_node));
+
+  if (vtv_debug)
+    {
+      /* Start: Arg types that only go into the debug version of the
+         function.  */
+      arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                       const_char_ptr_type));
+      arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                       const_char_ptr_type));
+      /* End: Arg types for debugging.  */
+    }
+
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+  register_pairs_type = build_function_type (register_pairs_type, arg_types);
+
+  if (vtv_debug)
+    vlt_register_pairs_fndecl = build_fn_decl ("__VLTRegisterPairDebug",
+                                               register_pairs_type);
+  else
+    vlt_register_pairs_fndecl = build_fn_decl ("__VLTRegisterPair",
+                                               register_pairs_type);
+
+  TREE_NOTHROW (vlt_register_pairs_fndecl) = 1;
+  DECL_ATTRIBUTES (vlt_register_pairs_fndecl) =
+                    tree_cons (get_identifier ("leaf"), NULL,
+                               DECL_ATTRIBUTES (vlt_register_pairs_fndecl));
+  TREE_PUBLIC (vlt_register_pairs_fndecl) = 1;
+  DECL_PRESERVE_P (vlt_register_pairs_fndecl) = 1;
+  retrofit_lang_decl (vlt_register_pairs_fndecl);
+  SET_DECL_LANGUAGE (vlt_register_pairs_fndecl, lang_cplusplus);
+
+  arg_types = build_tree_list (NULL_TREE, build_pointer_type (void_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   const_ptr_type_node));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   size_type_node));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+  init_set_symbol_type = build_function_type (init_set_symbol_type, arg_types);
+
+  if (vtv_debug)
+    vlt_init_set_symbol_fndecl = build_fn_decl ("__VLTInitSetSymbolDebug",
+                                                init_set_symbol_type);
+  else
+    vlt_init_set_symbol_fndecl = build_fn_decl ("__VLTInitSetSymbol",
+                                                init_set_symbol_type);
+
+  TREE_NOTHROW (vlt_init_set_symbol_fndecl) = 1;
+  DECL_ATTRIBUTES (vlt_init_set_symbol_fndecl) =
+                    tree_cons (get_identifier ("leaf"), NULL,
+                               DECL_ATTRIBUTES (vlt_init_set_symbol_fndecl));
+  TREE_PUBLIC (vlt_init_set_symbol_fndecl) = 1;
+  DECL_PRESERVE_P (vlt_init_set_symbol_fndecl) = 1;
+  retrofit_lang_decl (vlt_init_set_symbol_fndecl);
+  SET_DECL_LANGUAGE (vlt_init_set_symbol_fndecl, lang_cplusplus);
+}
+
+/* This is a helper function for
+   vtv_compute_class_hierarchy_transitive_closure.  It adds a
+   vtv_graph_node to the WORKLIST, which is a linked list of
+   seen-but-not-yet-processed nodes.  INSERTED is a bitmap, one bit
+   per node, to help make sure that we don't insert a node into the
+   worklist more than once.  Each node represents a class somewhere in
+   our class hierarchy information. Every node in the graph gets added
+   to the worklist exactly once and removed from the worklist exactly
+   once (when all of its children have been processed).  */
+
+static void
+add_to_worklist (struct work_node **worklist, struct vtv_graph_node *node,
+                 sbitmap inserted)
+{
+  struct work_node *new_work_node;
+
+  if (bitmap_bit_p (inserted, node->class_uid))
+    return;
+
+  new_work_node = XNEW (struct work_node);
+  new_work_node->next = *worklist;
+  new_work_node->node = node;
+  *worklist = new_work_node;
+
+  bitmap_set_bit (inserted, node->class_uid);
+}
+
+/* This is a helper function for
+   vtv_compute_class_hierarchy_transitive_closure.  It goes through
+   the WORKLIST of class hierarchy nodes looking for a "leaf" node,
+   i.e. a node whose children in the hierarchy have all been
+   processed.  When it finds the next leaf node, it removes it from
+   the linked list (WORKLIST) and returns the node.  */
+
+static struct vtv_graph_node *
+find_and_remove_next_leaf_node (struct work_node **worklist)
+{
+  struct work_node *prev, *cur;
+
+  for (prev = NULL, cur = *worklist; cur; prev = cur, cur = cur->next)
+    {
+      if (cur->node->num_children == cur->node->num_processed_children)
+        {
+          if (prev == NULL)
+            (*worklist) = cur->next;
+          else
+            prev->next = cur->next;
+
+          cur->next = NULL;
+          return cur->node;
+        }
+    }
+
+  return NULL;
+}
+
+/* In our class hierarchy graph, each class node contains a bitmap,
+   with one bit for each class in the hierarchy.  The bits are set for
+   classes that are descendants in the graph of the current node.
+   Initially the descendants bitmap is only set for immediate
+   descendants.  This function traverses the class hierarchy graph,
+   bottom up, filling in the transitive closures for the descendants
+   as we rise up the graph.  */
+
+void
+vtv_compute_class_hierarchy_transitive_closure (void)
+{
+  struct work_node *worklist = NULL;
+  struct vtbl_map_node *cur;
+  sbitmap inserted = sbitmap_alloc (num_vtable_map_nodes);
+  unsigned i;
+
+  /* Note: Every node in the graph gets added to the worklist exactly
+   once and removed from the worklist exactly once (when all of its
+   children have been processed).  Each node's children edges are
+   followed exactly once, and each node's parent edges are followed
+   exactly once.  So this algorithm is roughly O(V + 2E), i.e.
+   O(E + V).  */
+
+  /* Set-up:                                                                */
+  /* Find all the "leaf" nodes in the graph, and add them to the worklist.  */
+  bitmap_clear (inserted);
+  for (cur = vtbl_map_nodes; cur; cur = cur->next)
+    {
+      if (cur->class_info
+          && (cur->class_info->num_children == 0)
+          && ! (bitmap_bit_p (inserted, cur->class_info->class_uid)))
+        add_to_worklist (&worklist, cur->class_info, inserted);
+    }
+
+  /* Main work: pull next leaf node off work list, process it, add its
+     parents to the worklist, where a 'leaf' node is one that has no
+     children, or all of its children have been processed.  */
+  while (worklist)
+    {
+      struct vtv_graph_node *temp_node =
+                                  find_and_remove_next_leaf_node (&worklist);
+
+      gcc_assert (temp_node != NULL);
+      temp_node->descendants = sbitmap_alloc (num_vtable_map_nodes);
+      bitmap_clear (temp_node->descendants);
+      bitmap_set_bit (temp_node->descendants, temp_node->class_uid);
+      for (i = 0; i < temp_node->num_children; ++i)
+        bitmap_ior (temp_node->descendants, temp_node->descendants,
+                        temp_node->children[i]->descendants);
+      for (i = 0; i < temp_node->num_parents; ++i)
+        {
+          temp_node->parents[i]->num_processed_children =
+                    temp_node->parents[i]->num_processed_children + 1;
+          if (!bitmap_bit_p (inserted, temp_node->parents[i]->class_uid))
+            add_to_worklist (&worklist, temp_node->parents[i], inserted);
+        }
+    }
+}
+
+/* Keep track of which pairs we have already created __VLTRegisterPair
+   calls for, to prevent creating duplicate calls within the same
+   compilation unit.  VTABLE_DECL is the var decl for the vtable of
+   the (descendant) class that we are adding to our class hierarchy
+   data.  VPTR_ADDRESS is and expression for calculating the correct
+   offset into the vtable (VTABLE_DECL).  It is the actual vtable
+   pointer address that will be stored in our list of valid vtable
+   pointers for BASE_CLASS.  BASE_CLASS is the record_type node for
+   the base class to whose hiearchy we want to add
+   VPTR_ADDRESS. (VTABLE_DECL should be the vtable for BASE_CLASS or
+   one of BASE_CLASS' descendents.  */
+
+static bool
+record_register_pairs (tree vtable_decl, tree vptr_address,
+                       tree base_class)
+{
+  unsigned offset;
+  tree base_id;
+  struct vtbl_map_node *base_vtable_map_node;
+  tree class_type_decl;
+  tree type_decl_type;
+  unsigned int save_quals;
+  unsigned int null_quals = TYPE_UNQUALIFIED;
+
+  if (TREE_CODE (vptr_address) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (vptr_address, 0)) == MEM_REF)
+    vptr_address = TREE_OPERAND (vptr_address, 0);
+
+  offset = TREE_INT_CST_LOW (TREE_OPERAND (vptr_address, 1));
+
+  if (TREE_CHAIN (base_class))
+    class_type_decl = TREE_CHAIN (base_class);
+  else
+    class_type_decl = TYPE_NAME (base_class);
+
+  /* Temporarily remove any qualifiers on type.  */
+  type_decl_type = TREE_TYPE (class_type_decl);
+  save_quals = TYPE_QUALS (type_decl_type);
+  reset_type_qualifiers (null_quals, type_decl_type);
+
+  base_id = DECL_ASSEMBLER_NAME (TREE_CHAIN (base_class));
+  base_vtable_map_node = vtbl_map_get_node (base_id);
+
+  /* Restore any type qualifiers.  */
+  reset_type_qualifiers (save_quals, type_decl_type);
+
+  if (vtbl_map_node_registration_find (base_vtable_map_node, vtable_decl,
+                                       offset))
+    return true;
+
+  vtbl_map_node_registration_insert (base_vtable_map_node, vtable_decl,
+				     offset);
+  return false;
+}
+
+/* A class may contain secondary vtables in it, for various reasons.
+   This function goes through the decl chain of a class record looking
+   for any fields that point to secondary vtables, and adding calls to
+   __VLTRegisterPair for the secondary vtable pointers.
+
+   BASE_CLASS_DECL_ARG is an expression for the address of the vtable
+   map variable for the BASE_CLASS (whose hierarchy we are currently
+   updating).  BASE_CLASS is the record_type node for the base class.
+   RECORD_TYPE is the record_type node for the descendant class that
+   we are possibly adding to BASE_CLASS's hierarchy.  BODY is the
+   function body for the constructor init function to which we are
+   adding our calls to __VLTRegisterPair.  */
+
+static void
+register_vptr_fields (tree base_class_decl_arg, tree base_class,
+                      tree record_type, tree body)
+{
+  tree vtbl_var_decl;
+  tree arg1;
+  tree arg2;
+  int hint = 0;
+
+  if (TREE_CODE (record_type) != RECORD_TYPE)
+    return;
+
+  vtbl_var_decl = get_vtbl_decl_for_binfo (TYPE_BINFO (record_type));
+
+  if (vtbl_var_decl)
+    {
+      tree ztt_decl = DECL_CHAIN (vtbl_var_decl);
+      bool already_registered = false;
+
+      /* Check to see if we have found a constructor vtable.  Add its
+         data if appropriate.  */
+      if (ztt_decl != NULL_TREE && (DECL_NAME (ztt_decl))
+          && (strncmp (IDENTIFIER_POINTER (DECL_NAME (ztt_decl)),
+                       "_ZTT", 4) == 0))
+        {
+          tree values = DECL_INITIAL (ztt_decl);
+          struct varpool_node *vp_node = varpool_node_for_decl (ztt_decl);
+          if (vp_node->finalized
+              && TREE_ASM_WRITTEN (ztt_decl)
+              && values != NULL_TREE
+              && TREE_CODE (values) == CONSTRUCTOR
+              && TREE_CODE (TREE_TYPE (values)) == ARRAY_TYPE)
+            {
+              tree call_expr = NULL_TREE;
+              unsigned HOST_WIDE_INT cnt;
+              constructor_elt *ce;
+
+              /* Loop through the initialization values for this vtable to
+                 get all the correct vtable pointer addresses that we need
+                 to add to our set of valid vtable pointers for the current
+                 base class.  */
+
+              for (cnt = 0;
+                   vec_safe_iterate (CONSTRUCTOR_ELTS (values),
+                                     cnt, &ce);
+                   cnt++)
+                {
+                  tree value = ce->value;
+                  tree val_vtbl_decl = TREE_OPERAND (TREE_OPERAND (value, 0),
+                                                     0);
+                  int len1;
+                  int len2;
+
+                  if (TREE_CODE (val_vtbl_decl) == ADDR_EXPR
+                      && TREE_CODE (TREE_OPERAND (val_vtbl_decl, 0))
+                                                                   == VAR_DECL)
+                    val_vtbl_decl = TREE_OPERAND (val_vtbl_decl, 0);
+
+                  gcc_assert (TREE_CODE (val_vtbl_decl) == VAR_DECL);
+
+                  len1 = strlen (IDENTIFIER_POINTER
+				     (DECL_NAME
+				          (TREE_OPERAND
+					     (base_class_decl_arg, 0))));
+                  len2 = strlen (IDENTIFIER_POINTER
+				     (DECL_NAME (val_vtbl_decl)));
+                  arg1 = build_string_literal (len1 + 1,
+                                               IDENTIFIER_POINTER
+					        (DECL_NAME
+						 (TREE_OPERAND
+						  (base_class_decl_arg, 0))));
+                  arg2 = build_string_literal (len2 + 1,
+                                               IDENTIFIER_POINTER
+					        (DECL_NAME (val_vtbl_decl)));
+
+                  /* Check to see if we already have this vtable pointer in
+                     our valid set for this base class.  */
+
+                  already_registered = record_register_pairs (val_vtbl_decl,
+                                                              value,
+                                                              base_class);
+
+                  if (already_registered)
+                    continue;
+
+                  /* Generate the call to __VLTRegisterPair to add this
+                     vtable pointer to our set of valid pointers for the
+                     base class.  */
+
+                  if (vtv_debug)
+                    {
+                      call_expr = build_call_expr
+		                        (vlt_register_pairs_fndecl, 5,
+					 base_class_decl_arg, value,
+                                         build_int_cst (integer_type_node,
+                                                        hint),
+					 arg1, arg2);
+                    }
+                  else
+                    {
+                        call_expr = build_call_expr
+                                        (vlt_register_pairs_fndecl, 3,
+                                         base_class_decl_arg, value,
+                                         build_int_cst (integer_type_node,
+                                                        hint));
+                    }
+		  append_to_statement_list (call_expr, &body);
+                }
+            }
+        }
+    }
+}
+
+/* This function iterates through all the vtables it can find from the
+   BINFO of a class, to make sure we have found ALL of the vtables
+   that an object of that class could point to.  Generate calls to
+   __VLTRegisterPair for those vtable pointers that we find.
+
+   BINFO is the tree_binfo node for the BASE_CLASS.  BODY is the
+   function body for the constructor init function to which we are
+   adding calls to __VLTRegisterPair.  ARG1 is an expression for the
+   address of the vtable map variable (for the BASE_CLASS), that will
+   point to the updated data set.  BASE_CLASS is the record_type node
+   for the base class whose set of valid vtable pointers we are
+   updating. STR1 and STR2 are all debugging information, to be passed
+   as parameters to __VLTRegisterPairDebug.  STR1 represents the name
+   of the vtable map variable to be updated by the call.  Similarly,
+   STR2 represents the name of the class whose vtable pointer is being
+   added to the hierarchy.  */
+
+static void
+register_other_binfo_vtables (tree binfo, tree body, tree arg1, tree str1,
+                              tree str2, tree base_class)
+{
+  unsigned ix;
+  tree base_binfo;
+  tree vtable_decl;
+  bool already_registered;
+
+  if (binfo == NULL_TREE)
+    return;
+
+  for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
+    {
+      if ((!BINFO_PRIMARY_P (base_binfo)
+           || BINFO_VIRTUAL_P (base_binfo))
+          && (vtable_decl = get_vtbl_decl_for_binfo (base_binfo))
+          && !(DECL_VTABLE_OR_VTT_P (vtable_decl)
+               && DECL_CONSTRUCTION_VTABLE_P (vtable_decl)))
+        {
+          tree vtable_address = build_vtbl_address (base_binfo);
+          tree call_expr;
+
+          already_registered = record_register_pairs (vtable_decl,
+                                                      vtable_address,
+                                                      base_class);
+          if (!already_registered)
+            {
+              if (vtv_debug)
+                call_expr = build_call_expr (vlt_register_pairs_fndecl, 4,
+                                             arg1, vtable_address,
+                                             str1, str2);
+              else
+                call_expr = build_call_expr (vlt_register_pairs_fndecl, 2,
+                                             arg1, vtable_address);
+
+              append_to_statement_list (call_expr, &body);
+            }
+        }
+
+      register_other_binfo_vtables (base_binfo, body, arg1, str1, str2,
+                                    base_class);
+    }
+}
+
+/* The set of valid vtable pointers for any given class are stored in
+   a hash table.  For reasons of efficiency, that hash table size is
+   always a power of two.  In order to try to prevent re-sizing the
+   hash tables very often, we pass __VLTRegisterPair an initial guess
+   as to the number of entries the hashtable will eventually need
+   (rounded up to the nearest power of two).  This function takes the
+   class information we have collected for a particular class,
+   CLASS_NODE, and calculates the hash table size guess.  */
+
+static int
+guess_num_vtable_pointers (struct vtv_graph_node *class_node)
+{
+  tree vtbl;
+  int total_num_vtbls = 0;
+  int num_vtbls_power_of_two = 1;
+  unsigned i;
+
+  for (i = 0; i < num_vtable_map_nodes; ++i)
+    if (bitmap_bit_p (class_node->descendants, i))
+      {
+        tree class_type = vtbl_map_nodes_vec[i]->class_info->class_type;
+        for (vtbl = CLASSTYPE_VTABLES (class_type); vtbl;
+             vtbl = DECL_CHAIN (vtbl))
+          {
+            total_num_vtbls++;
+            if (total_num_vtbls > num_vtbls_power_of_two)
+              num_vtbls_power_of_two <<= 1;
+          }
+      }
+  return num_vtbls_power_of_two;
+}
+
+/* This function goes through our internal class hierarchy & vtable
+   pointer data structure and outputs calls to __VLTRegisterPair for
+   every class-vptr pair (for those classes whose vtable would be
+   output in the current compilation unit).  These calls get put into
+   our constructor initialization function.  BODY is the function
+   body, so far, of our constructor initialization function, to which we
+   add the calls.  */
+
+static bool
+register_all_pairs (tree body)
+{
+  struct vtbl_map_node *current;
+  bool registered_at_least_one = false;
+
+  for (current = vtbl_map_nodes; current; current = current->next)
+    {
+      unsigned i;
+      tree base_class = current->class_info->class_type;
+      tree base_ptr_var_decl = current->vtbl_map_decl;
+
+      gcc_assert (current->class_info != NULL);
+
+      tree str1 = NULL_TREE;
+
+      if (vtv_debug)
+        str1 = build_string_literal
+                        (IDENTIFIER_LENGTH (DECL_NAME (base_ptr_var_decl)) + 1,
+                         IDENTIFIER_POINTER (DECL_NAME (base_ptr_var_decl)));
+
+      for (i = 0; i < num_vtable_map_nodes; ++i)
+        if (bitmap_bit_p (current->class_info->descendants, i))
+          {
+            struct vtbl_map_node *vtbl_class_node = vtbl_map_nodes_vec[i];
+            tree class_type = vtbl_class_node->class_info->class_type;
+
+            if (class_type
+                && (TREE_CODE (class_type) == RECORD_TYPE))
+            {
+              tree new_type;
+              tree arg1;
+              tree call_expr;
+              bool already_registered;
+
+              tree binfo = TYPE_BINFO (class_type);
+              tree vtable_decl;
+              bool vtable_should_be_output = false;
+
+              vtable_decl = CLASSTYPE_VTABLES (class_type);
+
+              /* Handle main vtable for this class.  */
+
+              if (vtable_decl)
+                vtable_should_be_output = TREE_ASM_WRITTEN (vtable_decl);
+
+              if (vtable_decl && vtable_should_be_output
+                  && BINFO_VTABLE (binfo))
+                {
+                  tree vtable_address = build_vtbl_address (binfo);
+
+                  already_registered = record_register_pairs (vtable_decl,
+                                                              vtable_address,
+                                                              base_class);
+
+                  if (!already_registered)
+                    {
+                      int len2  = IDENTIFIER_LENGTH (DECL_NAME (vtable_decl));
+                      tree str2 = build_string_literal
+                                                   (len2 + 1,
+                                                    IDENTIFIER_POINTER
+                                                    (DECL_NAME (vtable_decl)));
+
+                      new_type = build_pointer_type (TREE_TYPE
+                                                     (base_ptr_var_decl));
+                      arg1 = build1 (ADDR_EXPR, new_type, base_ptr_var_decl);
+
+                      if (vtv_debug)
+                        /* This call expr has the 3 "real" arguments,
+                           plus 4 debugging arguments.  Eventually it
+                           will be replaced with the one just below
+                           it, which only has the 2 real
+                           arguments.  */
+                        call_expr = build_call_expr (vlt_register_pairs_fndecl,
+                                                     4, arg1, vtable_address,
+                                                     str1, str2);
+                      else
+                        call_expr = build_call_expr (vlt_register_pairs_fndecl,
+                                                     2, arg1, vtable_address);
+
+                      append_to_statement_list (call_expr, &body);
+
+                      registered_at_least_one = true;
+
+                      /* Find and handle any 'extra' vtables associated
+                         with this class, via virtual inheritance.   */
+                      register_vptr_fields (arg1, base_class, class_type,
+                                            body);
+
+                      /* Find and handle any 'extra' vtables associated
+                         with this class, via multiple inheritance.   */
+                      register_other_binfo_vtables (binfo, body, arg1, str1,
+                                                    str2, base_class);
+                    }
+                }
+            }
+          }
+    }
+
+  return registered_at_least_one;
+}
+
+/* Given a tree containing a class type (CLASS_TYPE), this function
+   finds and returns the class hierarchy node for that class in our
+   data structure.  */
+
+static struct vtv_graph_node *
+find_graph_node (tree class_type)
+{
+  tree class_decl = TREE_CHAIN (class_type);
+  tree class_name_id;
+  struct vtbl_map_node *vtbl_node;
+  tree class_decl_type;
+  tree type_decl_type;
+  unsigned int save_quals;
+  unsigned int null_quals = TYPE_UNQUALIFIED;
+
+  if (class_decl)
+    class_decl_type = class_decl;
+  else
+    class_decl_type = TYPE_NAME (class_type);
+
+  /* Temporarily remove any type qualifiers on the type.  */
+  type_decl_type = TREE_TYPE (class_decl_type);
+  save_quals = TYPE_QUALS (type_decl_type);
+  reset_type_qualifiers (null_quals, type_decl_type);
+
+  class_name_id = DECL_ASSEMBLER_NAME (class_decl_type);
+  vtbl_node = vtbl_map_get_node (class_name_id);
+
+  /* Restore the type qualifiers.  */
+  reset_type_qualifiers (save_quals, type_decl_type);
+
+  if (vtbl_node)
+    return vtbl_node->class_info;
+
+  return NULL;
+}
+
+/* This function adds an edge to our class hierarchy graph.
+   EDGE_ARRAY will either be an array of parent nodes or an array of
+   children nodes for a particular class.  NUM_ENTRIES is the current
+   number of entries in the array.  MAX_WENTRIES is the maximum number
+   of entries the array can hold.  NEW_ENTRY is a vtv_graph_node
+   representing the new child or parent node to be added to the
+   EDGE_ARRAY.  */
+
+static void
+add_edge_to_graph (struct vtv_graph_node ***edge_array, unsigned *num_entries,
+                   unsigned *max_entries, struct vtv_graph_node *new_entry)
+{
+  /* Check array size, and re-size it if necessary.  */
+  if (*num_entries >= ((*max_entries) - 1))
+    {
+      unsigned new_size = 2 * (*max_entries);
+      unsigned i;
+      *edge_array = (struct vtv_graph_node **)
+          xrealloc (*edge_array, new_size * sizeof (struct vtv_graph_node *));
+
+      for (i = *max_entries; i < new_size; ++i)
+        (*edge_array)[i] = NULL;
+      *max_entries = new_size;
+    }
+
+  (*edge_array)[*num_entries] = new_entry;
+  *num_entries = (*num_entries) + 1;
+}
+
+/* Add base class/derived class pair to our internal class hierarchy
+   data structure.  BASE_NODE is our vtv_graph_node that corresponds
+   to a base class.  DERIVED_NODE is our vtv_graph_node that
+   corresponds to a class that is a descendant of the base class
+   (possibly the base class itself).  */
+
+static void
+add_hierarchy_pair (struct vtv_graph_node *base_node,
+                    struct vtv_graph_node *derived_node)
+{
+  add_edge_to_graph (&(base_node->children), &(base_node->num_children),
+                     &(base_node->max_children), derived_node);
+  add_edge_to_graph (&(derived_node->parents), &(derived_node->num_parents),
+                     &(derived_node->max_parents), base_node);
+}
+
+/* This functions adds a new base class/derived class relationship to
+   our class hierarchy data structure.  Both parameters are trees
+   representing the class types, i.e. RECORD_TYPE trees.
+   DERIVED_CLASS can be the same as BASE_CLASS.  */
+
+static void
+update_class_hierarchy_information (tree base_class,
+                                    tree derived_class)
+{
+  struct vtv_graph_node *base_node = find_graph_node (base_class);
+  struct vtv_graph_node *derived_node = find_graph_node (derived_class);
+
+  add_hierarchy_pair (base_node, derived_node);
+}
+
+/* Generate an undefined variable (a reference) to a varible defined
+   in the vtv_init libraty. In that way, if the a module is not linked
+   with the vtv_init library, the linker will generate an undefined
+   symbol error.  Which is much better that getting a segmentation
+   violation at runtime.  The parameter, INIT_ROUTINE_BODY, is the
+   function body of our constructor initialization function, to which
+   we add the reference to this symbol (and all of our calls to
+   __VLTRegisterPair).
+
+   For more information, see comments in
+   libstdc++-v3/libsupc++/vtv_init.cc.  */
+
+static void
+create_undef_reference_to_vtv_init (tree init_routine_body)
+{
+  const char *vtv_init_undef_var = "__vtv_defined_in_vtv_init_lib";
+  tree var_decl;
+  tree init_zero;
+
+  var_decl  = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                          get_identifier (vtv_init_undef_var),
+                          int32_type_node);
+  TREE_PUBLIC (var_decl) = 1;
+  DECL_EXTERNAL (var_decl) = 1;
+  TREE_STATIC (var_decl) = 1;
+  SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (vtv_init_undef_var));
+  DECL_ARTIFICIAL (var_decl) = 1;
+  TREE_READONLY (var_decl) = 0;
+  DECL_IGNORED_P (var_decl) = 1;
+  DECL_PRESERVE_P (var_decl) = 1;
+  varpool_finalize_decl (var_decl);
+
+  /* Store a value in the undefined variable to force the creation of a
+     a reference.  */
+  init_zero = build2 (MODIFY_EXPR, TREE_TYPE (var_decl), var_decl,
+                      integer_zero_node);
+  append_to_statement_list (init_zero, &init_routine_body);
+
+}
+
+/* A simple hash function on strings */
+/* Be careful about changing this routine. The values generated will
+   be stored in the calls to InitSet. So, changing this routine may
+   cause a binary incompatibility.  */
+
+static uint32_t
+vtv_string_hash(const char *in)
+{
+  const char *s = in;
+  uint32_t h = 0;
+
+  gcc_assert (in != NULL);
+  for ( ; *s; ++s)
+    h = 5 * h + *s;
+  return h;
+}
+
+/* This function goes through all of our vtable map nodes, and for
+   each one that is actually used, it generates a call to
+   __VLTInitSetSymbol, with the appropriate arguments, and inserts the
+   calls as the start of our constructor initialization function
+   (INIT_ROUTINE_BODY).  */
+
+static bool
+init_all_sets (tree init_routine_body)
+{
+  struct vtbl_map_node *current;
+  bool inited_at_least_one = false;
+  tree_stmt_iterator i = tsi_start (init_routine_body);
+
+  for (current = vtbl_map_nodes; current; current = current->next)
+    {
+      if (!(current->is_used || (htab_elements (current->registered) > 0)))
+        continue;
+
+      size_t size_hint = guess_num_vtable_pointers (current->class_info);
+      tree set_handle_var_decl = current->vtbl_map_decl;
+
+      tree void_ptr_type = build_pointer_type
+                                             (TREE_TYPE (set_handle_var_decl));
+      tree arg1 = build1 (ADDR_EXPR, void_ptr_type, set_handle_var_decl);
+
+      uint32_t len1 = IDENTIFIER_LENGTH (DECL_NAME (set_handle_var_decl));
+      uint32_t hash_value = vtv_string_hash (IDENTIFIER_POINTER
+                                            (DECL_NAME (set_handle_var_decl)));
+      tree arg2, arg3, init_set_call;
+
+      /* Build a buffer with the memory representation of
+         insert_only_hash_map::key_value as defined in vtv_map.h. This
+         will be passed as the second argument to InitSet.  */
+      #define KEY_TYPE_FIXED_SIZE 8
+
+      void *key_buffer = xmalloc (len1 + KEY_TYPE_FIXED_SIZE);
+      uint32_t *value_ptr = (uint32_t *) key_buffer;
+
+      /* Set the len and hash for the string.  */
+      *value_ptr = len1;
+      value_ptr++;
+      *value_ptr = hash_value;
+
+      /* Now copy the string representation of the vtbl map name...  */
+      memcpy ((char *) key_buffer + KEY_TYPE_FIXED_SIZE,
+              IDENTIFIER_POINTER (DECL_NAME (set_handle_var_decl)),
+              len1);
+
+      /* ... and build a string literal from it. This will make a copy
+         so the key_bufffer is not needed anymore after this.  */
+      arg2 = build_string_literal (len1 + KEY_TYPE_FIXED_SIZE,
+                                   (char *) key_buffer);
+      free (key_buffer);
+
+      /* size_t maybe different at compile time vs at runtime but
+         there should not be a problem in here. We dont expect such
+         large number of elements in the set.  */
+      arg3 = build_int_cst (size_type_node, size_hint);
+      init_set_call = build_call_expr (vlt_init_set_symbol_fndecl,
+                                       3, arg1, arg2, arg3);
+      gcc_assert (size_hint != 0);
+      tsi_link_before (&i, init_set_call, TSI_SAME_STMT);
+
+      inited_at_least_one = true;
+    }
+  return inited_at_least_one;
+}
+
+
+/* This function calls register_all_pairs, which actually generates
+   all the calls to __VLTRegisterPair (in the verification constructor
+   init function).  It also generates the calls to
+   __VLTChangePermission, if the verification constructor init
+   function is going into the preinit array.  INIT_ROUTINE_BODY is
+   the body of our constructior initialization function, to which we
+   add our function calls.*/
+
+bool
+vtv_register_class_hierarchy_information (tree init_routine_body)
+{
+  bool registered_something = false;
+  bool inited_some_sets = true;
+
+  init_functions ();
+
+  /* TODO: Temp fix. Needs to be tightened.  */
+  if (num_vtable_map_nodes == 0)
+    return false;;
+
+  /* Add class hierarchy pairs to the vtable map data structure.  */
+  registered_something = register_all_pairs (init_routine_body);
+
+  /* Initialialize all vtable map variables (pointers to our data
+     sets.  */
+  inited_some_sets = init_all_sets (init_routine_body);
+
+  if (registered_something || inited_some_sets)
+  {
+      /* If this function is going into the preinit_array, then we
+         need to manually call __VLTChangePermission, rather than
+         depending on initialization prioritys in vtv_init.  */
+      if (flag_vtable_verify == VTV_PREINIT_PRIORITY)
+        {
+          /* Pass __VLTP_READ_WRITE value as defined in vtv_rts.h.  */
+          tree arg_read_write = build_int_cst (integer_type_node, 1);
+          tree arg_read_only = build_int_cst (integer_type_node, 0);
+
+          tree call_rw_expr = build_call_expr (vlt_change_permission_fndecl,
+                                               1, arg_read_write);
+          tree call_r_expr = build_call_expr (vlt_change_permission_fndecl,
+                                              1, arg_read_only);
+          tree_stmt_iterator i = tsi_start (init_routine_body);
+          /* Insert the call to make permissions read-write at the
+             beginning of the init routine.  */
+          tsi_link_before (&i, call_rw_expr, TSI_SAME_STMT);
+
+          /* Append the call to make permissions read-only at the
+             end of the init routine.  */
+          append_to_statement_list (call_r_expr, &init_routine_body);
+        }
+
+      if (flag_vtable_verify == VTV_STANDARD_PRIORITY)
+        create_undef_reference_to_vtv_init (init_routine_body);
+  }
+
+  return registered_something || inited_some_sets;
+}
+
+
+/* Generate the special constructor function that calls
+   __VLTChangePermission and __VLTRegisterPairs, and give it a very
+   high initialization priority.  */
+
+void
+vtv_generate_init_routine (void)
+{
+  tree init_routine_body;
+  bool vtable_classes_found = false;
+
+  push_lang_context (lang_name_c);
+
+  /* The priority for this init function (constructor) is carefully
+     chosen so that it will happen after the calls to unprotect the
+     memory used for vtable verification and before the memory is
+     protected again.  */
+  init_routine_body = vtv_start_verification_constructor_init_function ();
+
+  vtable_classes_found =
+                 vtv_register_class_hierarchy_information (init_routine_body);
+
+  if (vtable_classes_found)
+    {
+      current_function_decl =
+       vtv_finish_verification_constructor_init_function (init_routine_body);
+      allocate_struct_function (current_function_decl, false);
+      TREE_STATIC (current_function_decl) = 1;
+      TREE_USED (current_function_decl) = 1;
+      DECL_PRESERVE_P (current_function_decl) = 1;
+      if (flag_vtable_verify == VTV_PREINIT_PRIORITY)
+        {
+          DECL_STATIC_CONSTRUCTOR (current_function_decl) = 0;
+          assemble_vtv_preinit_initializer (current_function_decl);
+        }
+
+      gimplify_function_tree (current_function_decl);
+      cgraph_add_new_function (current_function_decl, false);
+
+      cgraph_process_new_functions ();
+    }
+  pop_lang_context ();
+}
+
+/* This funtion takes a tree containing a class type (BASE_TYPE), and
+   it either finds the existing vtbl_map_node for that class in our
+   data structure, or it creates a new node and adds it to the data
+   structure if there is not one for the class already.  As part of
+   this process it also creates the global vtable map variable for the
+   class.  */
+
+struct vtbl_map_node *
+vtable_find_or_create_map_decl (tree base_type)
+{
+  tree base_decl = TREE_CHAIN (base_type);
+  tree base_id;
+  char *var_name = NULL;
+  struct vtbl_map_node *vtable_map_node = NULL;
+  tree base_decl_type;
+  unsigned int save_quals;
+  unsigned int null_quals = TYPE_UNQUALIFIED;
+
+  /* Verify the type has an associated vtable.  */
+  if (!TYPE_BINFO (base_type) || !BINFO_VTABLE (TYPE_BINFO (base_type)))
+    return NULL;
+
+  if (!base_decl)
+    base_decl = TYPE_NAME (base_type);
+
+  /* Temporarily remove any type qualifiers on the type. */
+  base_decl_type = TREE_TYPE (base_decl);
+  save_quals = TYPE_QUALS (base_decl_type);
+  reset_type_qualifiers (null_quals, base_decl_type);
+
+  base_id = DECL_ASSEMBLER_NAME (base_decl);
+
+  /* Restore the type qualifiers. */
+  reset_type_qualifiers (save_quals, base_decl_type);
+
+  /* Create map lookup symbol for base class */
+  var_name = ACONCAT (("_ZN4_VTVI", IDENTIFIER_POINTER (base_id),
+                       "E12__vtable_mapE", NULL));
+  if (base_id)
+    /* We've already created the variable; just look it.  */
+    vtable_map_node = vtbl_map_get_node (base_id);
+
+  if (!vtable_map_node || (vtable_map_node->vtbl_map_decl == NULL_TREE))
+    {
+      /* If we haven't already created the *__vtable_map
+         global variable for this class, do so now, and
+         add it to the varpool, to make sure it gets saved
+         and written out.  */
+
+      char *sect_name = NULL;
+      tree var_decl = NULL;
+      tree var_type = build_pointer_type (void_type_node);
+      tree initial_value = build_int_cst (make_node (INTEGER_TYPE), 0);
+
+      var_decl  = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                              get_identifier (var_name), var_type);
+      TREE_PUBLIC (var_decl) = 1;
+      DECL_EXTERNAL (var_decl) = 0;
+      TREE_STATIC (var_decl) = 1;
+      DECL_VISIBILITY (var_decl) = VISIBILITY_HIDDEN;
+      SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (var_name));
+      DECL_ARTIFICIAL (var_decl) = 1;
+      /* We cannot mark this variable as read-only otherwise the gold
+         linker will not put it in the relro section. It seems if it
+         is marked as read-only, gold will put it in the .text
+         segment.  */
+      TREE_READONLY (var_decl) = 0;
+      DECL_IGNORED_P (var_decl) = 1;
+
+      /* Put these mmap variables in to data.rel.ro sections.
+	 It turns out this needs a previous fix in binutils as
+	 explained here:
+         http://sourceware.org/ml/binutils/2011-05/msg00083.html.  */
+
+      sect_name = ACONCAT ((".vtable_map_vars", NULL));
+
+      DECL_SECTION_NAME (var_decl) = build_string (strlen (sect_name),
+                                                   sect_name);
+      DECL_HAS_IMPLICIT_SECTION_NAME_P (var_decl) = true;
+      DECL_COMDAT_GROUP (var_decl) = get_identifier (var_name);
+      DECL_INITIAL (var_decl) = initial_value;
+
+      varpool_finalize_decl (var_decl);
+      if (!vtable_map_node)
+        vtable_map_node = find_or_create_vtbl_map_node (base_type);
+      if (vtable_map_node->vtbl_map_decl == NULL_TREE)
+        vtable_map_node->vtbl_map_decl = var_decl;
+    }
+
+  gcc_assert (vtable_map_node);
+  return vtable_map_node;
+}
+
+/* This function is used to build up our class hierarchy data for a
+   particular class.  TYPE is the record_type tree node for the
+   class.  */
+
+static void
+vtv_save_base_class_info (tree type)
+{
+  if (flag_vtable_verify)
+    {
+      tree binfo =  TYPE_BINFO (type);
+      tree base_binfo;
+      struct vtbl_map_node *own_map;
+      int i;
+
+      /* First make sure to create the map for this record type.  */
+      own_map = vtable_find_or_create_map_decl (type);
+      if (own_map == NULL)
+        return;
+
+      /* Go through the list of all base classes for the current
+         (derived) type, make sure the *__vtable_map global variable
+         for the base class exists, and add the base class/derived
+         class pair to the class hierarchy information we are
+         accumulating (for vtable pointer verification).  */
+      for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+        {
+          tree tree_val = BINFO_TYPE (base_binfo);
+          struct vtbl_map_node *vtable_map_node = NULL;
+
+          vtable_map_node = vtable_find_or_create_map_decl (tree_val);
+
+          if (vtable_map_node != NULL)
+            update_class_hierarchy_information (tree_val, type);
+        }
+    }
+}
+
+/* This function adds classes we are interested in to a list of
+   classes that is saved during pre-compiled header generation.
+   RECORD is the record_type node for the class we are adding to the
+   list.  */
+
+void
+vtv_save_class_info (tree record)
+{
+  if (!flag_vtable_verify || TREE_CODE (record) == UNION_TYPE)
+    return;
+
+  gcc_assert (TREE_CODE (record) == RECORD_TYPE);
+
+  vlt_saved_class_info = tree_cons (NULL_TREE, record, vlt_saved_class_info);
+}
+
+
+/* This function goes through the list of classes we saved before the
+   pre-compiled header generation and calls vtv_save_base_class_info
+   on each one, to build up our class hierarchy data structure.  */
+
+void
+vtv_recover_class_info (void)
+{
+  tree current_class;
+  tree class_chain = vlt_saved_class_info;
+  while (class_chain != NULL_TREE)
+    {
+      current_class = TREE_VALUE (class_chain);
+      gcc_assert (TREE_CODE (current_class) == RECORD_TYPE);
+
+      vtv_save_base_class_info (current_class);
+      class_chain = TREE_CHAIN (class_chain);
+    }
+
+  /* Let the garbabe collector collect the memory associated with the
+     chain.  */
+  vlt_saved_class_info = NULL_TREE;
+}
+
+#include "gt-cp-vtable-class-hierarchy.h"
Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c	(revision 195313)
+++ gcc/cp/mangle.c	(working copy)
@@ -3415,7 +3415,7 @@ mangle_decl_string (const tree decl)
 
 /* Return an identifier for the external mangled name of DECL.  */
 
-static tree
+tree
 get_mangled_id (tree decl)
 {
   tree id = mangle_decl_string (decl);
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 195313)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -5211,6 +5211,8 @@ extern void note_vague_linkage_fn		(tree
 extern tree build_artificial_parm		(tree, tree);
 extern bool possibly_inlined_p			(tree);
 extern int parm_index                           (tree);
+extern tree vtv_start_verification_constructor_init_function (void);
+extern tree vtv_finish_verification_constructor_init_function (tree);
 
 /* in error.c */
 extern void init_error				(void);
@@ -5298,6 +5300,7 @@ extern tree build_java_class_ref		(tree)
 extern tree integral_constant_value		(tree);
 extern tree decl_constant_value_safe	        (tree);
 extern int diagnose_uninitialized_cst_or_ref_member (tree, bool, bool);
+extern tree build_vtbl_address                  (tree);
 
 /* in lex.c */
 extern void cxx_dup_lang_specific_decl		(tree);
@@ -5525,6 +5528,11 @@ extern tree copied_binfo			(tree, tree);
 extern tree original_binfo			(tree, tree);
 extern int shared_member_p			(tree);
 
+/* in vtable-class-hierarchy.c */
+extern void vtv_compute_class_hierarchy_transitive_closure (void);
+extern void vtv_generate_init_routine           (void);
+extern void vtv_save_class_info                 (tree);
+extern void vtv_recover_class_info              (void);
 
 /* The representation of a deferred access check.  */
 
@@ -6006,6 +6014,7 @@ extern tree mangle_tls_init_fn			(tree);
 extern tree mangle_tls_wrapper_fn		(tree);
 extern bool decl_tls_wrapper_p			(tree);
 extern tree mangle_ref_init_variable		(tree);
+extern tree get_mangled_id                      (tree);
 
 /* in dump.c */
 extern bool cp_dump_tree			(void *, tree);

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-02-01 16:49 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CABtf2+ROV47=LoN7v2=R9ef7WVpwZVhtax6TLUu4vrQ-R0Ci-A@mail.gmail.com>
2013-01-30 17:44 ` [PATCH] Vtable pointer verification, C++ front end changes (patch 1 of 3) Jason Merrill
2013-02-01  0:25   ` Caroline Tice
2013-02-01 16:49     ` Jason Merrill
2013-01-23 22:35 Caroline Tice

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).