From patchwork Wed Apr 16 14:03:13 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Enkovich X-Patchwork-Id: 339597 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 8595B140096 for ; Thu, 17 Apr 2014 00:03:31 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=Titm4GacHrH3WdFp8y7myR3UK/SBAmlpf8rBHzfd0gUVQW89LkOIe PaRCqRlbPStlQvS913r0MnbNnFEDB+VtRQ6WQlzUH29u3MFbf37NWm8qMdABgsLF 6ZHFN3/SnhrTtu+AbSu1NjajyVLjpLXth4xcUc+tRHbxaNKPJeYN4Q= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=PNmzgdJxN/NyArAFYk1OsZxyeBk=; b=ESbtZjF+48481Fuy8nYT Q+RDwUr2FWTaU3QDRbmRt5sGIj6h1lJ4VNn5PtR5DQ6EVac7KVLT8/JmkXyfsac6 fwyKn1n12k2zUTFea2FU5XojqCAHTvudvRZ4LxjkXSVVkVy17M+fz6mjoEibMpjt g8bAO+lfvXiOatehRnFsG70= Received: (qmail 9201 invoked by alias); 16 Apr 2014 14:03:24 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 9192 invoked by uid 89); 16 Apr 2014 14:03:23 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.9 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-pb0-f50.google.com Received: from mail-pb0-f50.google.com (HELO mail-pb0-f50.google.com) (209.85.160.50) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Wed, 16 Apr 2014 14:03:21 +0000 Received: by mail-pb0-f50.google.com with SMTP id md12so10916441pbc.37 for ; Wed, 16 Apr 2014 07:03:19 -0700 (PDT) X-Received: by 10.68.131.202 with SMTP id oo10mr8765231pbb.35.1397656999627; Wed, 16 Apr 2014 07:03:19 -0700 (PDT) Received: from msticlxl57.ims.intel.com (fmdmzpr03-ext.fm.intel.com. [192.55.54.38]) by mx.google.com with ESMTPSA id pe3sm47271611pbc.23.2014.04.16.07.03.17 for (version=TLSv1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 16 Apr 2014 07:03:19 -0700 (PDT) Date: Wed, 16 Apr 2014 18:03:13 +0400 From: Ilya Enkovich To: gcc-patches@gcc.gnu.org Subject: [PATCH, Pointer Bounds Checker 9/x] Cgraph extension Message-ID: <20140416140313.GC41722@msticlxl57.ims.intel.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes Hi, This patch introduces changes in call graph for Pointer Bounds Checker. New fields instrumented_version, instrumentation_clone and orig_decl are added for cgraph_node: - instrumentation_clone field is 1 for nodes created for instrumented version of functions - instrumented_version points to instrumented/original node - orig_decl holds original function declaration for instrumented nodes in case original node is removed IPA_REF_CHKP reference type is introduced for nodes to reference instrumented function versions from originals. It is used to have proper reachability analysis. When original function bodies are not needed anymore, functions are transformed into thunks having call edge to the instrumented function. Therefore new field appeared in cgraph_thunk_info to mark such thunks. Does it look OK? Bootstrapped and tested on linux-x86_64. Thanks, Ilya --- gcc/ 2014-04-16 Ilya Enkovich * cgraph.h (cgraph_thunk_info): Add add_pointer_bounds_args field. (cgraph_node): Add instrumented_version, orig_decl and instrumentation_clone fields. (symtab_alias_target): Allow IPA_REF_CHKP reference. * cgraph.c (cgraph_remove_node): Fix instrumented_version of the referenced node if any. (dump_cgraph_node): Dump instrumentation_clone and instrumented_version fields. (verify_cgraph_node): Check correctness of IPA_REF_CHKP references and instrumentation thunks. * cgraphbuild.c (rebuild_cgraph_edges): Rebuild IPA_REF_CHKP reference. (cgraph_rebuild_references): Likewise. * cgraphunit.c (assemble_thunks_and_aliases): Skip thunks calling instrumneted function version. * ipa-ref.h (ipa_ref_use): Add IPA_REF_CHKP. (ipa_ref): increase size of use field. * ipa-ref.c (ipa_ref_use_name): Add element for IPA_REF_CHKP. * lto-cgraph.c (lto_output_node): Output instrumentation_clone, thunk.add_pointer_bounds_args and orig_decl field. (lto_output_ref): Adjust to new ipa_ref::use field size. (input_overwrite_node): Read instrumentation_clone field. (input_node): Read thunk.add_pointer_bounds_args and orig_decl fields. (input_ref): Adjust to new ipa_ref::use field size. (input_cgraph_1): Compute instrumented_version fields and restore IDENTIFIER_TRANSPARENT_ALIAS chains. * lto-streamer.h (LTO_minor_version): Change minor version from 0 to 1. * ipa.c (symtab_remove_unreachable_nodes): Consider instrumented clone as address taken if the original one is address taken. (cgraph_externally_visible_p): Mark instrumented 'main' as externally visible. (function_and_variable_visibility): Filter instrumentation thunks. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index be3661a..6210c68 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1828,6 +1828,12 @@ cgraph_remove_node (struct cgraph_node *node) } cgraph_n_nodes--; + if (node->instrumented_version) + { + node->instrumented_version->instrumented_version = NULL; + node->instrumented_version = NULL; + } + /* Clear out the node to NULL all pointers and add the node to the free list. */ memset (node, 0, sizeof (*node)); @@ -2070,6 +2076,11 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) if (indirect_calls_count) fprintf (f, " Has %i outgoing edges for indirect calls.\n", indirect_calls_count); + + if (node->instrumentation_clone) + fprintf (f, " Is instrumented version.\n"); + else if (node->instrumented_version) + fprintf (f, " Has instrumented version.\n"); } @@ -2850,7 +2861,9 @@ verify_cgraph_node (struct cgraph_node *node) } for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, 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; @@ -2868,6 +2881,35 @@ verify_cgraph_node (struct cgraph_node *node) error_found = true; } } + + /* Check all nodes reference their instrumented versions. */ + if (node->analyzed + && node->instrumented_version + && !node->instrumentation_clone) + { + bool ref_found = false; + int i; + struct ipa_ref *ref; + + for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, + i, ref); i++) + if (ref->use == IPA_REF_CHKP) + { + if (ref_found) + { + error ("Node has more than one chkp reference"); + error_found = true; + } + ref_found = true; + } + + if (!ref_found) + { + error ("Analyzed node has no reference to instrumented version"); + error_found = true; + } + } + if (node->analyzed && node->thunk.thunk_p) { if (!node->callees) @@ -2885,6 +2927,12 @@ verify_cgraph_node (struct cgraph_node *node) error ("Thunk is not supposed to have body"); error_found = true; } + if (node->thunk.add_pointer_bounds_args + && node->callees->callee != node->instrumented_version) + { + error ("Instrumentation thunk has wrong edge callee"); + error_found = true; + } } else if (node->analyzed && gimple_has_body_p (node->decl) && !TREE_ASM_WRITTEN (node->decl) diff --git a/gcc/cgraph.h b/gcc/cgraph.h index a6a51cf..5e702a7 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -191,6 +191,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; }; @@ -373,6 +374,13 @@ public: struct cgraph_node *prev_sibling_clone; struct cgraph_node *clones; struct 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. */ + struct 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; @@ -433,6 +441,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; }; @@ -1412,6 +1423,8 @@ symtab_alias_target (symtab_node *n) { struct ipa_ref *ref; ipa_ref_list_reference_iterate (&n->ref_list, 0, ref); + if (ref->use == IPA_REF_CHKP) + ipa_ref_list_reference_iterate (&n->ref_list, 1, ref); gcc_checking_assert (ref->use == IPA_REF_ALIAS); return ref->referred; } diff --git a/gcc/cgraphbuild.c b/gcc/cgraphbuild.c index 19961e2..a2b2106 100644 --- a/gcc/cgraphbuild.c +++ b/gcc/cgraphbuild.c @@ -481,6 +481,10 @@ rebuild_cgraph_edges (void) record_eh_tables (node, cfun); gcc_assert (!node->global.inlined_to); + if (node->instrumented_version + && !node->instrumentation_clone) + ipa_record_reference (node, node->instrumented_version, IPA_REF_CHKP, NULL); + return 0; } @@ -513,6 +517,11 @@ cgraph_rebuild_references (void) ipa_record_stmt_references (node, gsi_stmt (gsi)); } record_eh_tables (node, cfun); + + + if (node->instrumented_version + && !node->instrumentation_clone) + ipa_record_reference (node, node->instrumented_version, IPA_REF_CHKP, NULL); } namespace { diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 06283fc..ceb4060 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -1702,7 +1702,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; diff --git a/gcc/ipa-ref.c b/gcc/ipa-ref.c index 6aa41e6..3a055d9 100644 --- a/gcc/ipa-ref.c +++ b/gcc/ipa-ref.c @@ -27,7 +27,7 @@ along with GCC; see the file COPYING3. If not see #include "cgraph.h" #include "ipa-utils.h" -static const char *ipa_ref_use_name[] = {"read","write","addr","alias"}; +static const char *ipa_ref_use_name[] = {"read","write","addr","alias","chkp"}; /* Return ipa reference from REFERING_NODE or REFERING_VARPOOL_NODE to REFERED_NODE or REFERED_VARPOOL_NODE. USE_TYPE specify type diff --git a/gcc/ipa-ref.h b/gcc/ipa-ref.h index 4ce5f8d..d0df0bf 100644 --- a/gcc/ipa-ref.h +++ b/gcc/ipa-ref.h @@ -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. */ @@ -40,7 +41,7 @@ struct GTY(()) ipa_ref 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; }; diff --git a/gcc/ipa.c b/gcc/ipa.c index 5ab3aed..1d7fa35 100644 --- a/gcc/ipa.c +++ b/gcc/ipa.c @@ -508,6 +508,12 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) cgraph_node_remove_callees (node); ipa_remove_all_references (&node->ref_list); 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 @@ -583,7 +589,10 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) if (node->address_taken && !node->used_from_other_partition) { - if (!cgraph_for_node_and_aliases (node, has_addr_references_p, NULL, true)) + if (!cgraph_for_node_and_aliases (node, has_addr_references_p, NULL, true) + && (!node->instrumentation_clone + || !node->instrumented_version + || !node->instrumented_version->address_taken)) { if (file) fprintf (file, " %s", node->name ()); @@ -814,6 +823,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; } @@ -1016,6 +1029,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; diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index 999ce3d..58105f0 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -526,6 +526,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); if (node->thunk.thunk_p && !boundary_p) @@ -533,11 +534,15 @@ 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); } streamer_write_hwi_stream (ob->main_stream, node->profile_id); + + if (node->instrumentation_clone) + lto_output_fn_decl_index (ob->decl_state, ob->main_stream, node->orig_decl); } /* Output the varpool NODE to OB. @@ -613,7 +618,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); @@ -1002,6 +1007,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)); @@ -1112,10 +1118,19 @@ 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); node->profile_id = 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; } @@ -1196,7 +1211,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 = ipa_record_reference (referring_node, node, use, NULL); @@ -1337,6 +1352,22 @@ input_cgraph_1 (struct lto_file_decl_data *file_data, cgraph (node)->global.inlined_to = cgraph (nodes[ref]); else cnode->global.inlined_to = NULL; + + /* Compute instrumented_version. */ + if (cnode->instrumentation_clone) + { + gcc_assert (cnode->orig_decl); + + cnode->instrumented_version = cgraph_get_node (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; diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h index 51b1903..62a5fe0 100644 --- a/gcc/lto-streamer.h +++ b/gcc/lto-streamer.h @@ -141,7 +141,7 @@ along with GCC; see the file COPYING3. If not see #define LTO_SECTION_NAME_PREFIX ".gnu.lto_" #define LTO_major_version 3 -#define LTO_minor_version 0 +#define LTO_minor_version 1 typedef unsigned char lto_decl_flags_t;