diff mbox

Caller instrumentation with -finstrument-calls.

Message ID 1379403675-2866-2-git-send-email-paul_woegerer@mentor.com
State New
Headers show

Commit Message

Paul_Woegerer@mentor.com Sept. 17, 2013, 7:41 a.m. UTC
2013-07-01  Paul Woegerer  <paul_woegerer@mentor.com>

	Caller instrumentation with -finstrument-calls.
	* gcc/builtins.def: Add call-hooks __gnu_profile_call_before and
	__gnu_profile_call_after.
	* gcc/libfuncs.h (enum libfunc_index): Likewise.
	* gcc/optabs.c (init_optabs): Likewise.
	* gcc/c-family/c-common.c (no_instrument_calls): Add attribute.
	(handle_no_instrument_calls_attribute): New.
	* gcc/common.opt (finstrument-calls): New option.
	(finstrument-calls-exclude-function-list): Likewise.
	(finstrument-calls-exclude-file-list): Likewise.
	* gcc/opts.c (common_handle_option): Handle new options.
	* gcc/tree-core.h (tree_decl_with_vis): Add bitfield
	no_instrument_calls_before_after.
	* gcc/tree.h: Macro for no_instrument_calls_before_after access.
	* gcc/c/c-decl.c (merge_decls): Handle tree_function_decl field.
	* gcc/cp/decl.c (duplicate_decls): Likewise.
	* gcc/function.c (expand_function_start): Likewise.
	* gcc/ipa.c: Likewise.
	* gcc/java/jcf-parse.c: Likewise.
	* gcc/tree-streamer-in.c: Likewise.
	* gcc/tree-streamer-out.c: Likewise.
	(finstrument-calls-exclude-function-list): Likewise.
	(finstrument-calls-exclude-file-list): Likewise.
	* gcc/gimplify.c (flag_instrument_calls_exclude_p): New.
	(addr_expr_for_call_instrumentation): New.
	(maybe_add_profile_call): New.
	(gimplify_call_expr): Add call-hooks insertion.
	(gimplify_modify_expr): Likewise.
	* gcc/doc/invoke.texi: Added documentation for
	-finstrument-calls-exclude-function-list and
	-finstrument-calls-exclude-file-list and
	-finstrument-calls.
	* gcc/testsuite/g++.dg/other/instrument_calls-1.C  Added
	 regression test for -finstrument-calls.
	* gcc/testsuite/g++.dg/other/instrument_calls-2.C: Likewise.
	* gcc/testsuite/g++.dg/other/instrument_calls-3.C: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-1.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-2.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-3.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-4.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-5.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-6.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-7.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-8.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-9.c: Likewise.

Signed-off-by: Paul Woegerer <paul_woegerer@mentor.com>
---
 gcc/builtins.def                                |   5 ++
 gcc/c-family/c-common.c                         |  34 +++++++
 gcc/c/c-decl.c                                  |   2 +
 gcc/common.opt                                  |  20 ++++-
 gcc/cp/decl.c                                   |   2 +
 gcc/doc/invoke.texi                             |  42 +++++++++
 gcc/function.c                                  |   3 +-
 gcc/gimplify.c                                  | 113 +++++++++++++++++++++++-
 gcc/ipa.c                                       |   1 +
 gcc/java/jcf-parse.c                            |   1 +
 gcc/libfuncs.h                                  |   6 ++
 gcc/optabs.c                                    |   6 ++
 gcc/opts.c                                      |  10 +++
 gcc/testsuite/g++.dg/other/instrument_calls-1.C |  14 +++
 gcc/testsuite/g++.dg/other/instrument_calls-2.C |  20 +++++
 gcc/testsuite/g++.dg/other/instrument_calls-3.C |  17 ++++
 gcc/testsuite/gcc.dg/instrument_calls-1.c       |   8 ++
 gcc/testsuite/gcc.dg/instrument_calls-2.c       |   8 ++
 gcc/testsuite/gcc.dg/instrument_calls-3.c       |   8 ++
 gcc/testsuite/gcc.dg/instrument_calls-4.c       |   8 ++
 gcc/testsuite/gcc.dg/instrument_calls-5.c       |  11 +++
 gcc/testsuite/gcc.dg/instrument_calls-6.c       |  11 +++
 gcc/testsuite/gcc.dg/instrument_calls-7.c       |  13 +++
 gcc/testsuite/gcc.dg/instrument_calls-8.c       |   7 ++
 gcc/testsuite/gcc.dg/instrument_calls-9.c       |  12 +++
 gcc/tree-core.h                                 |   4 +-
 gcc/tree-streamer-in.c                          |   2 +
 gcc/tree-streamer-out.c                         |   1 +
 gcc/tree.h                                      |   6 ++
 29 files changed, 390 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/other/instrument_calls-1.C
 create mode 100644 gcc/testsuite/g++.dg/other/instrument_calls-2.C
 create mode 100644 gcc/testsuite/g++.dg/other/instrument_calls-3.C
 create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-1.c
 create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-2.c
 create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-3.c
 create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-4.c
 create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-5.c
 create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-6.c
 create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-7.c
 create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-8.c
 create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-9.c
diff mbox

Patch

diff --git a/gcc/builtins.def b/gcc/builtins.def
index 8ccf3ae..fc60cc7 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -805,6 +805,11 @@  DEF_BUILTIN (BUILT_IN_PROFILE_FUNC_ENTER, "__cyg_profile_func_enter", BUILT_IN_N
 DEF_BUILTIN (BUILT_IN_PROFILE_FUNC_EXIT, "__cyg_profile_func_exit", BUILT_IN_NORMAL, BT_FN_VOID_PTR_PTR, BT_LAST,
 	     false, false, false, ATTR_NULL, true, true)
 
+DEF_BUILTIN (BUILT_IN_PROFILE_CALL_BEFORE, "__gnu_profile_call_before", BUILT_IN_NORMAL, BT_FN_VOID_PTR, BT_LAST,
+	     false, false, false, ATTR_NULL, true, true)
+DEF_BUILTIN (BUILT_IN_PROFILE_CALL_AFTER, "__gnu_profile_call_after", BUILT_IN_NORMAL, BT_FN_VOID_PTR, BT_LAST,
+	     false, false, false, ATTR_NULL, true, true)
+
 /* TLS thread pointer related builtins.  */
 DEF_BUILTIN (BUILT_IN_THREAD_POINTER, "__builtin_thread_pointer",
 	     BUILT_IN_NORMAL, BT_FN_PTR, BT_LAST,
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 62aa9fc..d145283 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -343,6 +343,8 @@  static tree handle_tls_model_attribute (tree *, tree, tree, int,
 					bool *);
 static tree handle_no_instrument_function_attribute (tree *, tree,
 						     tree, int, bool *);
+static tree handle_no_instrument_calls_attribute (tree *, tree,
+						     tree, int, bool *);
 static tree handle_malloc_attribute (tree *, tree, tree, int, bool *);
 static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
 static tree handle_no_limit_stack_attribute (tree *, tree, tree, int,
@@ -660,6 +662,9 @@  const struct attribute_spec c_common_attribute_table[] =
   { "no_instrument_function", 0, 0, true,  false, false,
 			      handle_no_instrument_function_attribute,
 			      false },
+  { "no_instrument_calls", 0, 0, true,  false, false,
+			      handle_no_instrument_calls_attribute,
+			      false },
   { "malloc",                 0, 0, true,  false, false,
 			      handle_malloc_attribute, false },
   { "returns_twice",          0, 0, true,  false, false,
@@ -7920,6 +7925,35 @@  handle_no_instrument_function_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
+/* Handle a "no_instrument_calls" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_no_instrument_calls_attribute (tree *node, tree name,
+					 tree ARG_UNUSED (args),
+					 int ARG_UNUSED (flags),
+					 bool *no_add_attrs)
+{
+  tree decl = *node;
+
+  if (TREE_CODE (decl) != FUNCTION_DECL)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+		"%qE attribute applies only to functions", name);
+      *no_add_attrs = true;
+    }
+  else if (DECL_INITIAL (decl))
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+		"can%'t set %qE attribute after definition", name);
+      *no_add_attrs = true;
+    }
+  else
+    DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (decl) = 1;
+
+  return NULL_TREE;
+}
+
 /* Handle a "malloc" attribute; arguments as in
    struct attribute_spec.handler.  */
 
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index f7ae648..e65f29c 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2287,6 +2287,8 @@  merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
 	  DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
 	  DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
 	    |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
+	  DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (newdecl)
+	    |= DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (olddecl);
 	  TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
 	  DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
 	  DECL_IS_OPERATOR_NEW (newdecl) |= DECL_IS_OPERATOR_NEW (olddecl);
diff --git a/gcc/common.opt b/gcc/common.opt
index fae9763..da4b176 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -93,7 +93,7 @@  int flag_gen_aux_info = 0
 Variable
 int flag_shlib
 
-; These two are really VEC(char_p,heap) *.
+; These four are really VEC(char_p,heap) *.
 
 Variable
 void *flag_instrument_functions_exclude_functions
@@ -101,6 +101,12 @@  void *flag_instrument_functions_exclude_functions
 Variable
 void *flag_instrument_functions_exclude_files
 
+Variable
+void *flag_instrument_calls_exclude_functions
+
+Variable
+void *flag_instrument_calls_exclude_files
+
 ; Generic structs (e.g. templates not explicitly specialized)
 ; may not have a compilation unit associated with them, and so
 ; may need to be treated differently from ordinary structs.
@@ -1368,6 +1374,18 @@  finstrument-functions-exclude-file-list=
 Common RejectNegative Joined
 -finstrument-functions-exclude-file-list=filename,...  Do not instrument functions listed in files
 
+finstrument-calls
+Common Report Var(flag_instrument_calls_before_after)
+Instrument call entry and exit with profiling calls
+
+finstrument-calls-exclude-function-list=
+Common RejectNegative Joined
+-finstrument-calls-exclude-function-list=name,...  Do not instrument calls from listed functions
+
+finstrument-calls-exclude-file-list=
+Common RejectNegative Joined
+-finstrument-calls-exclude-file-list=filename,...  Do not instrument calls from functions listed in files
+
 fipa-cp
 Common Report Var(flag_ipa_cp) Optimization
 Perform interprocedural constant propagation
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 6e026b2..c6e5327 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1977,6 +1977,8 @@  duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
 	{
 	  DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
 	    |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
+	  DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (newdecl)
+	    |= DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (olddecl);
 	  DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
 	  TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
 	  TREE_NOTHROW (newdecl) |= TREE_NOTHROW (olddecl);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index caca744..0cccbf2 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1026,6 +1026,9 @@  See S/390 and zSeries Options.
 -finhibit-size-directive  -finstrument-functions @gol
 -finstrument-functions-exclude-function-list=@var{sym},@var{sym},@dots{} @gol
 -finstrument-functions-exclude-file-list=@var{file},@var{file},@dots{} @gol
+-finstrument-calls @gol
+-finstrument-calls-exclude-function-list=@var{sym},@var{sym},@dots{} @gol
+-finstrument-calls-exclude-file-list=@var{file},@var{file},@dots{} @gol
 -fno-common  -fno-ident @gol
 -fpcc-struct-return  -fpic  -fPIC -fpie -fPIE @gol
 -fno-jump-tables @gol
@@ -20976,6 +20979,45 @@  of the function name, it is considered to be a match.  For C99 and C++
 extended identifiers, the function name must be given in UTF-8, not
 using universal character names.
 
+@item -finstrument-calls
+@opindex finstrument-calls
+Generate instrumentation calls immediately before and after each
+function call. The following profiling functions will be called with
+the address of the function that is called between them. Use
+@code{__builtin_return_address(0)} inside the profiling functions to
+get the addresses from where they are called.
+
+@smallexample
+void __gnu_profile_call_before (void *fn);
+void __gnu_profile_call_after  (void *fn);
+@end smallexample
+
+A function may be given attribute @code{no_instrument_calls}, in which
+case the instrumentation is omitted (no calls within that function will
+be instrumented). 
+
+In addition, calls to functions which have been given attribute
+@code{no_instrument_function} (or selected via
+@code{-finstrument-functions-exclude} options) are also excluded from
+instrumentation.
+
+@item -finstrument-calls-exclude-file-list=@var{file},@var{file},@dots{}
+@opindex finstrument-calls-exclude-file-list
+
+Set the list of functions that are excluded from instrumentation (see
+the description of @code{-finstrument-calls}).  If the file that
+contains a function definition matches with one of @var{file}, then
+the calls in that function are not instrumented.  The match is done on
+substrings as for @code{-finstrument-functions-exclude-file-list}.
+
+@item -finstrument-calls-exclude-function-list=@var{sym},@var{sym},@dots{}
+@opindex finstrument-calls-exclude-function-list
+
+This is similar to @code{-finstrument-calls-exclude-file-list},
+but this option sets the list of function names to be excluded from
+instrumentation.  The function name to be matched in the same way as for
+@code{-finstrument-functions-exclude-function-list}
+
 @item -fstack-check
 @opindex fstack-check
 Generate code to verify that you do not go beyond the boundary of the
diff --git a/gcc/function.c b/gcc/function.c
index c7d259c..a03a69d 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4757,7 +4757,8 @@  expand_function_start (tree subr)
 
   crtl->profile
     = (profile_flag
-       && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr));
+       && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr)
+       && ! DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (subr));
 
   crtl->limit_stack
     = (stack_limit_rtx != NULL_RTX && ! DECL_NO_LIMIT_STACK (subr));
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 1589db4..7047490 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -91,6 +91,8 @@  static struct gimplify_omp_ctx *gimplify_omp_ctxp;
 
 /* Forward declaration.  */
 static enum gimplify_status gimplify_compound_expr (tree *, gimple_seq *, bool);
+static bool flag_instrument_calls_exclude_p (tree fndecl);
+static bool flag_instrument_functions_exclude_p (tree fndecl);
 
 /* Mark X addressable.  Unlike the langhook we expect X to be in gimple
    form and we don't do any syntax checking.  */
@@ -1157,6 +1159,63 @@  build_stack_save_restore (gimple *save, gimple *restore)
 			 1, tmp_var);
 }
 
+/* Returns the function decl that corresponds the function called in
+   CALL_EXPR if call instrumentation is enabled.  */
+
+static tree
+addr_expr_for_call_instrumentation (tree call_expr)
+{
+  tree addr_expr = NULL_TREE;
+
+  if (!gimplify_ctxp->into_ssa && flag_instrument_calls_before_after
+      && !DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (current_function_decl)
+      && !flag_instrument_calls_exclude_p (current_function_decl))
+    {
+      tree fndecl = get_callee_fndecl (call_expr);
+      if (fndecl)
+        {
+	  if (!DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl)
+	      && !flag_instrument_functions_exclude_p (fndecl))
+	    {
+	      if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+		      && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_APPLY
+		      && call_expr_nargs (call_expr) > 0)
+		  addr_expr = CALL_EXPR_ARG (call_expr, 0);
+	      else if (!DECL_IS_BUILTIN (fndecl))
+		  addr_expr = build_fold_addr_expr (fndecl);
+	    }
+        }
+      else
+	  addr_expr = CALL_EXPR_FN (call_expr);
+    }
+
+  if (addr_expr)
+    {
+      if (TREE_CODE (addr_expr) == OBJ_TYPE_REF)
+	addr_expr = OBJ_TYPE_REF_EXPR (addr_expr);
+      else if (!is_gimple_val (addr_expr))
+	addr_expr = NULL_TREE;
+    }
+
+  return addr_expr;
+}
+
+/* Prepare call to PROFILE_CALL_* builtin (specified by CODE) for
+   function with decl FNDECL and add it to the sequence of GIMPLE
+   statements in PRE_P.  */
+
+static void
+maybe_add_profile_call (tree addr_expr, enum built_in_function code,
+			gimple_seq *pre_p)
+{
+  if (addr_expr)
+    {
+      tree x = builtin_decl_implicit (code);
+      gimple call = gimple_build_call (x, 1, addr_expr);
+      gimplify_seq_add_stmt (pre_p, call);
+    }
+}
+
 /* Gimplify a BIND_EXPR.  Just voidify and recurse.  */
 
 static enum gimplify_status
@@ -2690,15 +2749,22 @@  gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
      gimplify_modify_expr.  */
   if (!want_value)
     {
+      tree addr_expr = addr_expr_for_call_instrumentation (*expr_p);
+      gimple_stmt_iterator gsi;
+
+      maybe_add_profile_call (addr_expr, BUILT_IN_PROFILE_CALL_BEFORE, pre_p);
+
       /* The CALL_EXPR in *EXPR_P is already in GIMPLE form, so all we
 	 have to do is replicate it as a GIMPLE_CALL tuple.  */
-      gimple_stmt_iterator gsi;
       call = gimple_build_call_from_tree (*expr_p);
       gimple_call_set_fntype (call, TREE_TYPE (fnptrtype));
       notice_special_calls (call);
       gimplify_seq_add_stmt (pre_p, call);
       gsi = gsi_last (*pre_p);
       fold_stmt (&gsi);
+
+      maybe_add_profile_call (addr_expr, BUILT_IN_PROFILE_CALL_AFTER, pre_p);
+
       *expr_p = NULL_TREE;
     }
   else
@@ -4800,6 +4866,7 @@  gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
   gimple assign;
   location_t loc = EXPR_LOCATION (*expr_p);
   gimple_stmt_iterator gsi;
+  tree addr_expr = NULL_TREE;
 
   gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR
 	      || TREE_CODE (*expr_p) == INIT_EXPR);
@@ -4929,9 +4996,13 @@  gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 
   if (TREE_CODE (*from_p) == CALL_EXPR)
     {
+      tree fnptrtype;
+
+      addr_expr = addr_expr_for_call_instrumentation (*from_p);
+
       /* Since the RHS is a CALL_EXPR, we need to create a GIMPLE_CALL
 	 instead of a GIMPLE_ASSIGN.  */
-      tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (*from_p));
+      fnptrtype = TREE_TYPE (CALL_EXPR_FN (*from_p));
       CALL_EXPR_FN (*from_p) = TREE_OPERAND (CALL_EXPR_FN (*from_p), 0);
       STRIP_USELESS_TYPE_CONVERSION (CALL_EXPR_FN (*from_p));
       assign = gimple_build_call_from_tree (*from_p);
@@ -4952,7 +5023,9 @@  gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
       gcc_assert (TREE_CODE (*to_p) == SSA_NAME);
     }
 
+  maybe_add_profile_call (addr_expr, BUILT_IN_PROFILE_CALL_BEFORE, pre_p);
   gimplify_seq_add_stmt (pre_p, assign);
+  maybe_add_profile_call (addr_expr, BUILT_IN_PROFILE_CALL_AFTER, pre_p);
   gsi = gsi_last (*pre_p);
   fold_stmt (&gsi);
 
@@ -8447,6 +8520,42 @@  flag_instrument_functions_exclude_p (tree fndecl)
   return false;
 }
 
+/* Return whether we should exclude FNDECL from call instrumentation.  */
+
+static bool
+flag_instrument_calls_exclude_p (tree fndecl)
+{
+  vec<char_p> *v;
+
+  v = (vec<char_p> *) flag_instrument_calls_exclude_functions;
+  if (v && v->length () > 0)
+    {
+      const char *name;
+      int i;
+      char *s;
+
+      name = lang_hooks.decl_printable_name (fndecl, 0);
+      FOR_EACH_VEC_ELT (*v, i, s)
+	if (strstr (name, s) != NULL)
+	  return true;
+    }
+
+  v = (vec<char_p> *) flag_instrument_calls_exclude_files;
+  if (v && v->length () > 0)
+    {
+      const char *name;
+      int i;
+      char *s;
+
+      name = DECL_SOURCE_FILE (fndecl);
+      FOR_EACH_VEC_ELT (*v, i, s)
+	if (strstr (name, s) != NULL)
+	  return true;
+    }
+
+  return false;
+}
+
 /* Entry point to the gimplification pass.  FNDECL is the FUNCTION_DECL
    node for the function we want to gimplify.
 
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 91d63eb..a3da75b 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -1299,6 +1299,7 @@  cgraph_build_static_cdtor_1 (char which, tree body, int priority, bool final)
   TREE_USED (decl) = 1;
   DECL_ARTIFICIAL (decl) = 1;
   DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
+  DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (decl) = 1;
   DECL_SAVED_TREE (decl) = body;
   if (!targetm.have_ctors_dtors && final)
     {
diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c
index fbd4e00..5ead4a6 100644
--- a/gcc/java/jcf-parse.c
+++ b/gcc/java/jcf-parse.c
@@ -1715,6 +1715,7 @@  java_emit_static_constructor (void)
       TREE_USED (decl) = 1;
       DECL_ARTIFICIAL (decl) = 1;
       DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
+      DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (decl) = 1;
       DECL_SAVED_TREE (decl) = body;
       DECL_UNINLINABLE (decl) = 1;
 
diff --git a/gcc/libfuncs.h b/gcc/libfuncs.h
index 04a4dc2..4c7faa4 100644
--- a/gcc/libfuncs.h
+++ b/gcc/libfuncs.h
@@ -40,6 +40,9 @@  enum libfunc_index
   LTI_profile_function_entry,
   LTI_profile_function_exit,
 
+  LTI_profile_call_before,
+  LTI_profile_call_after,
+
   LTI_synchronize,
 
   LTI_gcov_flush,
@@ -98,6 +101,9 @@  extern struct target_libfuncs *this_target_libfuncs;
 #define profile_function_entry_libfunc	(libfunc_table[LTI_profile_function_entry])
 #define profile_function_exit_libfunc	(libfunc_table[LTI_profile_function_exit])
 
+#define profile_call_before_libfunc	(libfunc_table[LTI_profile_call_before])
+#define profile_call_after_libfunc	(libfunc_table[LTI_profile_call_after])
+
 #define synchronize_libfunc	(libfunc_table[LTI_synchronize])
 
 #define gcov_flush_libfunc	(libfunc_table[LTI_gcov_flush])
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 1d0659e..31c91b9 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -6207,6 +6207,12 @@  init_optabs (void)
   profile_function_exit_libfunc
     = init_one_libfunc ("__cyg_profile_func_exit");
 
+  /* For call before/after instrumentation.  */
+  profile_call_before_libfunc
+    = init_one_libfunc ("__gnu_profile_call_before");
+  profile_call_after_libfunc
+    = init_one_libfunc ("__gnu_profile_call_after");
+
   gcov_flush_libfunc = init_one_libfunc ("__gcov_flush");
 
   /* Allow the target to add more libcalls or rename some, etc.  */
diff --git a/gcc/opts.c b/gcc/opts.c
index 6b6652d..1df54ae 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1605,6 +1605,16 @@  common_handle_option (struct gcc_options *opts,
 	(&opts->x_flag_instrument_functions_exclude_files, arg);
       break;
 
+    case OPT_finstrument_calls_exclude_function_list_:
+      add_comma_separated_to_vector
+	(&opts->x_flag_instrument_calls_exclude_functions, arg);
+      break;
+
+    case OPT_finstrument_calls_exclude_file_list_:
+      add_comma_separated_to_vector
+	(&opts->x_flag_instrument_calls_exclude_files, arg);
+      break;
+
     case OPT_fmessage_length_:
       pp_set_line_maximum_length (dc->printer, value);
       diagnostic_set_caret_max_width (dc, value);
diff --git a/gcc/testsuite/g++.dg/other/instrument_calls-1.C b/gcc/testsuite/g++.dg/other/instrument_calls-1.C
new file mode 100644
index 0000000..68e00c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/instrument_calls-1.C
@@ -0,0 +1,14 @@ 
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+class Base
+{
+public:
+	virtual void foo();
+};
+
+void fn_caller( Base* b ) { b->foo(); }
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
+
diff --git a/gcc/testsuite/g++.dg/other/instrument_calls-2.C b/gcc/testsuite/g++.dg/other/instrument_calls-2.C
new file mode 100644
index 0000000..0a295e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/instrument_calls-2.C
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+#define CALL_MEMBER_FN(object,ptrToMember)  ((object).*(ptrToMember))
+
+class Base
+{
+public:
+	virtual void foo();
+	virtual void bar();
+	virtual void foobar(int i);
+	virtual void barfoo(int i);
+};
+
+typedef void (Base::*BaseMemFn)(int i);
+void fn_caller( Base& obj, BaseMemFn memfnptr ) { CALL_MEMBER_FN(obj, memfnptr)(42); }
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
+
diff --git a/gcc/testsuite/g++.dg/other/instrument_calls-3.C b/gcc/testsuite/g++.dg/other/instrument_calls-3.C
new file mode 100644
index 0000000..e96280a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/instrument_calls-3.C
@@ -0,0 +1,17 @@ 
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+class Base
+{
+public:
+	int bar();
+};
+
+int fn_caller( Base& b )
+{
+   b.bar();
+}
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
+
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-1.c b/gcc/testsuite/gcc.dg/instrument_calls-1.c
new file mode 100644
index 0000000..c406448
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-1.c
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+void fn () { }
+void fn_caller () { fn (); }
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-2.c b/gcc/testsuite/gcc.dg/instrument_calls-2.c
new file mode 100644
index 0000000..8be35be
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-2.c
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls -finstrument-calls-exclude-function-list=fn_caller" } */
+
+void fn () { }
+void fn_caller () { fn (); }
+
+/* { dg-final { scan-assembler-not "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler-not "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-3.c b/gcc/testsuite/gcc.dg/instrument_calls-3.c
new file mode 100644
index 0000000..ad14987
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-3.c
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls -finstrument-calls-exclude-file-list=instrument_calls-3" } */
+
+void fn () { }
+void fn_caller () { fn (); }
+
+/* { dg-final { scan-assembler-not "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler-not "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-4.c b/gcc/testsuite/gcc.dg/instrument_calls-4.c
new file mode 100644
index 0000000..ef95a89
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-4.c
@@ -0,0 +1,8 @@ 
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+#include <stdio.h>
+void fn_caller () { puts (""); }
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-5.c b/gcc/testsuite/gcc.dg/instrument_calls-5.c
new file mode 100644
index 0000000..be567d7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-5.c
@@ -0,0 +1,11 @@ 
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+int fn (int i) { }
+int fn_caller (int i)
+{
+    return fn (i);
+}
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-6.c b/gcc/testsuite/gcc.dg/instrument_calls-6.c
new file mode 100644
index 0000000..38a2605
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-6.c
@@ -0,0 +1,11 @@ 
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+void fn_caller ()
+{
+    void fn () { }
+    fn ();
+}
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-7.c b/gcc/testsuite/gcc.dg/instrument_calls-7.c
new file mode 100644
index 0000000..e6d9503
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-7.c
@@ -0,0 +1,13 @@ 
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+void *p_fn[3];
+int fn_caller (int i, char *fmt, ...)
+{
+    void *arg = __builtin_apply_args();
+    void *ret = __builtin_apply(p_fn[i], arg, 0xff);
+    __builtin_return(ret);
+}
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-8.c b/gcc/testsuite/gcc.dg/instrument_calls-8.c
new file mode 100644
index 0000000..57d021b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-8.c
@@ -0,0 +1,7 @@ 
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+void fn_caller ( void (*p_fn)() ) { p_fn (); }
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-9.c b/gcc/testsuite/gcc.dg/instrument_calls-9.c
new file mode 100644
index 0000000..ec67040
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-9.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+__attribute__((no_instrument_function)) void fn ();
+
+void fn_caller ()
+{
+    fn ();
+}
+
+/* { dg-final { scan-assembler-not "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler-not "__gnu_profile_call_after" } } */
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index b1bc56a..8a2a464 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1309,7 +1309,9 @@  struct GTY(()) tree_decl_with_vis {
  unsigned cxx_destructor : 1;
  /* Belong to FUNCTION_DECL exclusively.  */
  unsigned final : 1;
- /* 11 unused bits. */
+ /* Belong to FUNCTION_DECL exclusively.  */
+ unsigned no_instrument_calls_before_after : 1;
+ /* 10 unused bits. */
 };
 
 struct GTY(()) tree_var_decl {
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
index c36d4f6..be74fb2 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -308,6 +308,8 @@  unpack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
   DECL_NO_INLINE_WARNING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr)
     			= (unsigned) bp_unpack_value (bp, 1);
+  DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (expr)
+			= (unsigned) bp_unpack_value (bp, 1);
   DECL_NO_LIMIT_STACK (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_DISREGARD_INLINE_LIMITS (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
diff --git a/gcc/tree-streamer-out.c b/gcc/tree-streamer-out.c
index 942ba1e..549b26c 100644
--- a/gcc/tree-streamer-out.c
+++ b/gcc/tree-streamer-out.c
@@ -276,6 +276,7 @@  pack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
   bp_pack_value (bp, DECL_STATIC_CHAIN (expr), 1);
   bp_pack_value (bp, DECL_NO_INLINE_WARNING_P (expr), 1);
   bp_pack_value (bp, DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr), 1);
+  bp_pack_value (bp, DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (expr), 1);
   bp_pack_value (bp, DECL_NO_LIMIT_STACK (expr), 1);
   bp_pack_value (bp, DECL_DISREGARD_INLINE_LIMITS (expr), 1);
   bp_pack_value (bp, DECL_PURE_P (expr), 1);
diff --git a/gcc/tree.h b/gcc/tree.h
index a263a2c..25f8c14 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2543,6 +2543,12 @@  extern vec<tree, va_gc> **decl_debug_args_insert (tree);
 #define DECL_FINAL_P(NODE)\
    (FUNCTION_DECL_CHECK (NODE)->decl_with_vis.final)
 
+/* Used in FUNCTION_DECL to indicate that function calls in that function
+   should be instrumented with calls to support routines before and after
+   each function call.  */
+#define DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER(NODE) \
+   (FUNCTION_DECL_CHECK (NODE)->decl_with_vis.no_instrument_calls_before_after)
+
 /* The source language of the translation-unit.  */
 #define TRANSLATION_UNIT_LANGUAGE(NODE) \
   (TRANSLATION_UNIT_DECL_CHECK (NODE)->translation_unit_decl.language)