@@ -1823,6 +1823,12 @@ cgraph_node::remove (void)
}
cgraph_n_nodes--;
+ if (instrumented_version)
+ {
+ instrumented_version->instrumented_version = NULL;
+ instrumented_version = NULL;
+ }
+
/* Clear out the node to NULL all pointers and add the node to the free
list. */
memset (this, 0, sizeof (*this));
@@ -2069,6 +2075,11 @@ cgraph_node::dump (FILE *f)
if (indirect_calls_count)
fprintf (f, " Has %i outgoing edges for indirect calls.\n",
indirect_calls_count);
+
+ if (instrumentation_clone)
+ fprintf (f, " Is instrumented version.\n");
+ else if (instrumented_version)
+ fprintf (f, " Has instrumented version.\n");
}
/* Dump call graph node NODE to stderr. */
@@ -2834,7 +2845,9 @@ cgraph_node::verify_node (void)
error_found = true;
}
for (i = 0; iterate_reference (i, ref); i++)
- if (ref->use != IPA_REF_ALIAS)
+ if (ref->use == IPA_REF_CHKP)
+ ;
+ else if (ref->use != IPA_REF_ALIAS)
{
error ("Alias has non-alias reference");
error_found = true;
@@ -2852,6 +2865,64 @@ cgraph_node::verify_node (void)
error_found = true;
}
}
+
+ /* Check instrumented version reference. */
+ if (instrumented_version
+ && instrumented_version->instrumented_version != this)
+ {
+ error ("Instrumentation clone does not reference original node");
+ error_found = true;
+ }
+
+ /* Cannot have orig_decl for not instrumented nodes. */
+ if (!instrumentation_clone && orig_decl)
+ {
+ error ("Not instrumented node has non-NULL original declaration");
+ error_found = true;
+ }
+
+ /* If original not instrumented node still exists then we may check
+ original declaration is set properly. */
+ if (instrumented_version
+ && orig_decl
+ && orig_decl != instrumented_version->decl)
+ {
+ error ("Instrumented node has wrong original declaration");
+ error_found = true;
+ }
+
+ /* Check all nodes have chkp reference to their instrumented versions. */
+ if (analyzed
+ && instrumented_version
+ && !instrumentation_clone)
+ {
+ bool ref_found = false;
+ int i;
+ struct ipa_ref *ref;
+
+ for (i = 0; iterate_reference (i, ref); i++)
+ if (ref->use == IPA_REF_CHKP)
+ {
+ if (ref_found)
+ {
+ error ("Node has more than one chkp reference");
+ error_found = true;
+ }
+ if (ref->referred != instrumented_version)
+ {
+ error ("Wrong node is referenced with chkp reference");
+ error_found = true;
+ }
+ ref_found = true;
+ }
+
+ if (!ref_found)
+ {
+ error ("Analyzed node has no reference to instrumented version");
+ error_found = true;
+ }
+ }
+
if (analyzed && thunk.thunk_p)
{
if (!callees)
@@ -2869,6 +2940,12 @@ cgraph_node::verify_node (void)
error ("Thunk is not supposed to have body");
error_found = true;
}
+ if (thunk.add_pointer_bounds_args
+ && !instrumented_version->semantically_equivalent_p (callees->callee))
+ {
+ error ("Instrumentation thunk has wrong edge callee");
+ error_found = true;
+ }
}
else if (analyzed && gimple_has_body_p (decl)
&& !TREE_ASM_WRITTEN (decl)
@@ -516,6 +516,7 @@ struct GTY(()) cgraph_thunk_info {
tree alias;
bool this_adjusting;
bool virtual_offset_p;
+ bool add_pointer_bounds_args;
/* Set to true when alias node is thunk. */
bool thunk_p;
};
@@ -1139,6 +1140,13 @@ public:
cgraph_node *prev_sibling_clone;
cgraph_node *clones;
cgraph_node *clone_of;
+ /* If instrumentation_clone is 1 then instrumented_version points
+ to the original function used to make instrumented version.
+ Otherwise points to instrumented version of the function. */
+ cgraph_node *instrumented_version;
+ /* If instrumentation_clone is 1 then orig_decl is the original
+ function declaration. */
+ tree orig_decl;
/* For functions with many calls sites it holds map from call expression
to the edge to speed up cgraph_edge function. */
htab_t GTY((param_is (struct cgraph_edge))) call_site_hash;
@@ -1199,6 +1207,9 @@ public:
/* True if this decl calls a COMDAT-local function. This is set up in
compute_inline_parameters and inline_call. */
unsigned calls_comdat_local : 1;
+ /* True when function is clone created for Pointer Bounds Checker
+ instrumentation. */
+ unsigned instrumentation_clone : 1;
};
/* A cgraph node set is a collection of cgraph nodes. A cgraph node
@@ -1690,6 +1701,8 @@ symtab_node::get_alias_target (void)
{
struct ipa_ref *ref = NULL;
iterate_reference (0, ref);
+ if (ref->use == IPA_REF_CHKP)
+ iterate_reference (1, ref);
gcc_checking_assert (ref->use == IPA_REF_ALIAS);
return ref->referred;
}
@@ -458,6 +458,10 @@ rebuild_cgraph_edges (void)
record_eh_tables (node, cfun);
gcc_assert (!node->global.inlined_to);
+ if (node->instrumented_version
+ && !node->instrumentation_clone)
+ node->add_reference (node->instrumented_version, IPA_REF_CHKP, NULL);
+
return 0;
}
@@ -490,6 +494,10 @@ cgraph_rebuild_references (void)
node->record_stmt_references (gsi_stmt (gsi));
}
record_eh_tables (node, cfun);
+
+ if (node->instrumented_version
+ && !node->instrumentation_clone)
+ node->add_reference (node->instrumented_version, IPA_REF_CHKP, NULL);
}
namespace {
@@ -1705,7 +1705,8 @@ assemble_thunks_and_aliases (struct cgraph_node *node)
struct ipa_ref *ref;
for (e = node->callers; e;)
- if (e->caller->thunk.thunk_p)
+ if (e->caller->thunk.thunk_p
+ && !e->caller->thunk.add_pointer_bounds_args)
{
struct cgraph_node *thunk = e->caller;
@@ -29,7 +29,8 @@ enum GTY(()) ipa_ref_use
IPA_REF_LOAD,
IPA_REF_STORE,
IPA_REF_ADDR,
- IPA_REF_ALIAS
+ IPA_REF_ALIAS,
+ IPA_REF_CHKP
};
/* Record of reference in callgraph or varpool. */
@@ -54,7 +55,7 @@ public:
gimple stmt;
unsigned int lto_stmt_uid;
unsigned int referred_index;
- ENUM_BITFIELD (ipa_ref_use) use:2;
+ ENUM_BITFIELD (ipa_ref_use) use:3;
unsigned int speculative:1;
};
@@ -260,6 +260,10 @@ cgraph_externally_visible_p (struct cgraph_node *node,
if (MAIN_NAME_P (DECL_NAME (node->decl)))
return true;
+ if (node->instrumentation_clone
+ && MAIN_NAME_P (DECL_NAME (node->orig_decl)))
+ return true;
+
return false;
}
@@ -535,6 +539,7 @@ function_and_variable_visibility (bool whole_program)
}
if (node->thunk.thunk_p
+ && !node->thunk.add_pointer_bounds_args
&& TREE_PUBLIC (node->decl))
{
struct cgraph_node *decl_node = node;
@@ -490,6 +490,12 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
node->remove_from_same_comdat_group ();
node->remove_all_references ();
changed = true;
+ if (node->thunk.thunk_p
+ && node->thunk.add_pointer_bounds_args)
+ {
+ node->thunk.thunk_p = false;
+ node->thunk.add_pointer_bounds_args = false;
+ }
}
}
else
@@ -564,7 +570,10 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
&& !node->used_from_other_partition)
{
if (!node->call_for_symbol_thunks_and_aliases
- (has_addr_references_p, NULL, true))
+ (has_addr_references_p, NULL, true)
+ && (!node->instrumentation_clone
+ || !node->instrumented_version
+ || !node->instrumented_version->address_taken))
{
if (file)
fprintf (file, " %s", node->name ());
@@ -541,6 +541,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
bp_pack_value (&bp, node->thunk.thunk_p && !boundary_p, 1);
bp_pack_enum (&bp, ld_plugin_symbol_resolution,
LDPR_NUM_KNOWN, node->resolution);
+ bp_pack_value (&bp, node->instrumentation_clone, 1);
streamer_write_bitpack (&bp);
streamer_write_data_stream (ob->main_stream, section, strlen (section) + 1);
@@ -549,7 +550,8 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
streamer_write_uhwi_stream
(ob->main_stream,
1 + (node->thunk.this_adjusting != 0) * 2
- + (node->thunk.virtual_offset_p != 0) * 4);
+ + (node->thunk.virtual_offset_p != 0) * 4
+ + (node->thunk.add_pointer_bounds_args != 0) * 8);
streamer_write_uhwi_stream (ob->main_stream, node->thunk.fixed_offset);
streamer_write_uhwi_stream (ob->main_stream, node->thunk.virtual_value);
}
@@ -558,6 +560,9 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
streamer_write_hwi_stream (ob->main_stream, node->get_init_priority ());
if (DECL_STATIC_DESTRUCTOR (node->decl))
streamer_write_hwi_stream (ob->main_stream, node->get_fini_priority ());
+
+ if (node->instrumentation_clone)
+ lto_output_fn_decl_index (ob->decl_state, ob->main_stream, node->orig_decl);
}
/* Output the varpool NODE to OB.
@@ -656,7 +661,7 @@ lto_output_ref (struct lto_simple_output_block *ob, struct ipa_ref *ref,
struct cgraph_node *node;
bp = bitpack_create (ob->main_stream);
- bp_pack_value (&bp, ref->use, 2);
+ bp_pack_value (&bp, ref->use, 3);
bp_pack_value (&bp, ref->speculative, 1);
streamer_write_bitpack (&bp);
nref = lto_symtab_encoder_lookup (encoder, ref->referred);
@@ -1080,6 +1085,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data,
node->thunk.thunk_p = bp_unpack_value (bp, 1);
node->resolution = bp_unpack_enum (bp, ld_plugin_symbol_resolution,
LDPR_NUM_KNOWN);
+ node->instrumentation_clone = bp_unpack_value (bp, 1);
gcc_assert (flag_ltrans
|| (!node->in_other_partition
&& !node->used_from_other_partition));
@@ -1203,6 +1209,7 @@ input_node (struct lto_file_decl_data *file_data,
node->thunk.this_adjusting = (type & 2);
node->thunk.virtual_value = virtual_value;
node->thunk.virtual_offset_p = (type & 4);
+ node->thunk.add_pointer_bounds_args = (type & 8);
}
if (node->alias && !node->analyzed && node->weakref)
node->alias_target = get_alias_symbol (node->decl);
@@ -1211,6 +1218,14 @@ input_node (struct lto_file_decl_data *file_data,
node->set_init_priority (streamer_read_hwi (ib));
if (DECL_STATIC_DESTRUCTOR (node->decl))
node->set_fini_priority (streamer_read_hwi (ib));
+
+ if (node->instrumentation_clone)
+ {
+ decl_index = streamer_read_uhwi (ib);
+ fn_decl = lto_file_decl_data_get_fn_decl (file_data, decl_index);
+ node->orig_decl = fn_decl;
+ }
+
return node;
}
@@ -1307,7 +1322,7 @@ input_ref (struct lto_input_block *ib,
struct ipa_ref *ref;
bp = streamer_read_bitpack (ib);
- use = (enum ipa_ref_use) bp_unpack_value (&bp, 2);
+ use = (enum ipa_ref_use) bp_unpack_value (&bp, 3);
speculative = (enum ipa_ref_use) bp_unpack_value (&bp, 1);
node = nodes[streamer_read_hwi (ib)];
ref = referring_node->add_reference (node, use);
@@ -1449,6 +1464,22 @@ input_cgraph_1 (struct lto_file_decl_data *file_data,
= dyn_cast<cgraph_node *> (nodes[ref]);
else
cnode->global.inlined_to = NULL;
+
+ /* Compute instrumented_version. */
+ if (cnode->instrumentation_clone)
+ {
+ gcc_assert (cnode->orig_decl);
+
+ cnode->instrumented_version = cgraph_node::get (cnode->orig_decl);
+ if (cnode->instrumented_version)
+ cnode->instrumented_version->instrumented_version = cnode;
+
+ /* Restore decl names reference. */
+ if (IDENTIFIER_TRANSPARENT_ALIAS (DECL_ASSEMBLER_NAME (cnode->decl))
+ && !TREE_CHAIN (DECL_ASSEMBLER_NAME (cnode->decl)))
+ TREE_CHAIN (DECL_ASSEMBLER_NAME (cnode->decl))
+ = DECL_ASSEMBLER_NAME (cnode->orig_decl);
+ }
}
ref = (int) (intptr_t) node->same_comdat_group;
@@ -45,7 +45,7 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-utils.h"
#include "calls.h"
-static const char *ipa_ref_use_name[] = {"read","write","addr","alias"};
+static const char *ipa_ref_use_name[] = {"read","write","addr","alias","chkp"};
const char * const ld_plugin_symbol_resolution_names[]=
{