Hello,

On PowerPC targets with -mlongcall, most subprogram calls are turned into indirect calls: the call target is read from a register even though it is compile-time known. This makes it difficult for machine code static analysis engines to recover the callee information. The attached patch is an attempt to help such engines, generating DW_AT_abstract_origin attributes for all DW_TAG_GNU_call_site we are interested in.

Here is how it works:

1. At -O0, the var-tracking pass is disabled, so in order to get a NOTE_INSN_CALL_ARG_LOCATION for each call we are interested in, this patch creates a new "naive" var-tracking pass. When optimizing, the regular var-tracking pass does this job and this new pass is disabled.

2. The DWARF back-end (dwarf2out.c) first registers this RTL note (in dwarf2out_var_location, already existing code) and extracts the corresponding callee function symbol reference (new code to add handling for the case we are interested in).

There, the patch also relaxes assertions in gen_subprogram_die: yes, we can have both a compile-time known call target and an indirect call. Already existing code in gen_subprogram_die calls gen_call_site_die and takes care of generating the corresponding debug information.

Bootstrapped and regtested on x86_64-pc-linux-gnu and powerpc-linux-gnu: no regression. Ok for trunk? Thank you in advance for your feedback!

gcc/ChangeLog:

        * passes.def: Add a new pass: variable_tracking_no_opt.
        * rtl.h (variable_tracking_no_opt_main): New.
        * tree-pass.h (make_pass_variable_tracking_no_opt): New.
        * var-tracking.c (variable_tracking_no_opt_main,
        pass_data_variable_tracking_no_opt,
        pass_variable_tracking_no_opt,
        make_pass_variable_tracking_no_opt): New.  Implement the new
        pass which adds notes for indirect calls.
        * dwarf2out.c (dwarf2out_var_location): Set the symbol reference
        for calls whose target is compile-time known but that are
        indirect.
        (gen_subprogram_die): Handle such calls.

--
Pierre-Marie de Rodat

>From 1fee786f51baca25f1363cd82f207cd67f48e69f Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <dero...@adacore.com>
Date: Thu, 13 Jun 2013 11:13:08 +0200
Subject: [PATCH] Track indirect calls for call site information in debug info.

gcc/ChangeLog:

	* passes.def: Add a new pass: variable_tracking_no_opt.
	* rtl.h (variable_tracking_no_opt_main): New.
	* tree-pass.h (make_pass_variable_tracking_no_opt): New.
	* var-tracking.c (variable_tracking_no_opt_main,
	pass_data_variable_tracking_no_opt,
	pass_variable_tracking_no_opt,
	make_pass_variable_tracking_no_opt): New.  Implement the new
	pass which adds notes for indirect calls.
	* dwarf2out.c (dwarf2out_var_location): Set the symbol reference
	for calls whose target is compile-time known but that are
	indirect.
	(gen_subprogram_die): Handle such calls.
---
 gcc/dwarf2out.c    |  46 +++++++++++++++---------
 gcc/passes.def     |   1 +
 gcc/rtl.h          |   1 +
 gcc/tree-pass.h    |   1 +
 gcc/var-tracking.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 135 insertions(+), 16 deletions(-)

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 2834d57..a6bcb48 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -19219,18 +19219,23 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 		    }
 		  if (mode == VOIDmode || mode == BLKmode)
 		    continue;
-		  if (XEXP (XEXP (arg, 0), 0) == pc_rtx)
+		  /* Sometimes, the target of a call is compile-time known, but
+		     for various reasons, there is still an indirect call
+		     instruction: do not output redundant debug information for
+		     them.  */
+		  if (ca_loc->symbol_ref == NULL_RTX)
 		    {
-		      gcc_assert (ca_loc->symbol_ref == NULL_RTX);
-		      tloc = XEXP (XEXP (arg, 0), 1);
-		      continue;
-		    }
-		  else if (GET_CODE (XEXP (XEXP (arg, 0), 0)) == CLOBBER
-			   && XEXP (XEXP (XEXP (arg, 0), 0), 0) == pc_rtx)
-		    {
-		      gcc_assert (ca_loc->symbol_ref == NULL_RTX);
-		      tlocc = XEXP (XEXP (arg, 0), 1);
-		      continue;
+		      if (XEXP (XEXP (arg, 0), 0) == pc_rtx)
+			{
+			  tloc = XEXP (XEXP (arg, 0), 1);
+			  continue;
+			}
+		      else if (GET_CODE (XEXP (XEXP (arg, 0), 0)) == CLOBBER
+			       && XEXP (XEXP (XEXP (arg, 0), 0), 0) == pc_rtx)
+			{
+			  tlocc = XEXP (XEXP (arg, 0), 1);
+			  continue;
+			}
 		    }
 		  reg = NULL;
 		  if (REG_P (XEXP (XEXP (arg, 0), 0)))
@@ -22344,11 +22349,20 @@ dwarf2out_var_location (rtx_insn *loc_note)
       x = get_call_rtx_from (PATTERN (prev));
       if (x)
 	{
-	  x = XEXP (XEXP (x, 0), 0);
-	  if (GET_CODE (x) == SYMBOL_REF
-	      && SYMBOL_REF_DECL (x)
-	      && TREE_CODE (SYMBOL_REF_DECL (x)) == FUNCTION_DECL)
-	    ca_loc->symbol_ref = x;
+	  /* Try to get the call symbol, if any.  */
+	  if (MEM_P (XEXP (x, 0)))
+	    x = XEXP (x, 0);
+	  /* First, look for a memory access to a symbol_ref.  */
+	  if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+	      && SYMBOL_REF_DECL (XEXP (x, 0))
+	      && TREE_CODE (SYMBOL_REF_DECL (XEXP (x, 0))) == FUNCTION_DECL)
+	    ca_loc->symbol_ref = XEXP (x, 0);
+	  /* Otherwise, look at a compile-time known user-level function
+	     declaration.  */
+	  else if (MEM_P (x)
+		   && MEM_EXPR (x)
+		   && TREE_CODE (MEM_EXPR (x)) == FUNCTION_DECL)
+	    ca_loc->symbol_ref = XEXP (DECL_RTL (MEM_EXPR (x)), 0);
 	}
       ca_loc->block = insn_scope (prev);
       if (call_arg_locations)
diff --git a/gcc/passes.def b/gcc/passes.def
index 6b66f8f..d65e380 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -446,6 +446,7 @@ along with GCC; see the file COPYING3.  If not see
       PUSH_INSERT_PASSES_WITHIN (pass_late_compilation)
 	  NEXT_PASS (pass_compute_alignments);
 	  NEXT_PASS (pass_variable_tracking);
+	  NEXT_PASS (pass_variable_tracking_no_opt);
 	  NEXT_PASS (pass_free_cfg);
 	  NEXT_PASS (pass_machine_reorg);
 	  NEXT_PASS (pass_cleanup_barriers);
diff --git a/gcc/rtl.h b/gcc/rtl.h
index f363ed4..5be307d 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3648,6 +3648,7 @@ extern GTY(()) rtx stack_limit_rtx;
 
 /* In var-tracking.c */
 extern unsigned int variable_tracking_main (void);
+extern unsigned int variable_tracking_no_opt_main (void);
 
 /* In stor-layout.c.  */
 extern void get_mode_bounds (machine_mode, int, machine_mode,
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index c47b22e..67ad558 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -576,6 +576,7 @@ extern rtl_opt_pass *make_pass_df_finish (gcc::context *ctxt);
 extern rtl_opt_pass *make_pass_compute_alignments (gcc::context *ctxt);
 extern rtl_opt_pass *make_pass_duplicate_computed_gotos (gcc::context *ctxt);
 extern rtl_opt_pass *make_pass_variable_tracking (gcc::context *ctxt);
+extern rtl_opt_pass *make_pass_variable_tracking_no_opt (gcc::context *ctxt);
 extern rtl_opt_pass *make_pass_free_cfg (gcc::context *ctxt);
 extern rtl_opt_pass *make_pass_machine_reorg (gcc::context *ctxt);
 extern rtl_opt_pass *make_pass_cleanup_barriers (gcc::context *ctxt);
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index da9de28..03187f9 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -121,6 +121,7 @@
 #include "recog.h"
 #include "rtl-iter.h"
 #include "fibonacci_heap.h"
+#include "debug.h"
 
 typedef fibonacci_heap <long, basic_block_def> bb_heap_t;
 typedef fibonacci_node <long, basic_block_def> bb_heap_node_t;
@@ -10325,6 +10326,61 @@ variable_tracking_main (void)
   return ret;
 }
 
+/* Entry point for the naive variable tracking pass.  Add notes for indirect
+   calls in each basic block.  */
+
+unsigned int
+variable_tracking_no_opt_main (void)
+{
+  basic_block bb;
+
+  /* Look for every call instruction and add an empty note right after
+     them if needed.  */
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      rtx_insn *insn;
+
+      FOR_BB_INSNS (bb, insn)
+	{
+	  rtx x;
+
+	  /* We are at -O0 so do not bother about dealing with SEQUENCEs.  */
+	  if (!INSN_P (insn))
+	    continue;
+	  x = PATTERN (insn);
+	  if (GET_CODE (x) == PARALLEL)
+	    x = XVECEXP (x, 0, 0);
+	  if (GET_CODE (x) == SET)
+	    x = SET_SRC (x);
+	  if (GET_CODE (x) == CALL)
+	    {
+	      x = XEXP (x, 0);
+
+	      /* The purpose of this pass is to add notes after some call
+		 instructions so that debug info is generated for them.  The
+		 goal is to make it possible to get the call target by looking
+		 either at the call instruction or, when this is not sufficient
+		 (like with indirect calls), at the corresponding debug
+		 information.  */
+	      if (!MEM_P (x)
+		  || GET_CODE (XEXP (x, 0)) != SYMBOL_REF
+		  || !SYMBOL_REF_DECL (XEXP (x, 0))
+		  || (TREE_CODE (SYMBOL_REF_DECL (XEXP (x, 0)))
+		      != FUNCTION_DECL))
+		{
+		  /* Emit a not only for calls that have a pattern that is not:
+		     (call (mem (symbol_ref some_function_decl))).  */
+		  rtx note
+		    = emit_note_after (NOTE_INSN_CALL_ARG_LOCATION, insn);
+		  NOTE_VAR_LOCATION (note) = NULL;
+		}
+	    }
+	}
+    }
+
+  return 0;
+}
+
 namespace {
 
 const pass_data pass_data_variable_tracking =
@@ -10360,6 +10416,46 @@ public:
 
 }; // class pass_variable_tracking
 
+const pass_data pass_data_variable_tracking_no_opt =
+{
+  RTL_PASS, /* type */
+  "no-opt vartrack", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_VAR_TRACKING,/* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0 /* todo_flags_finish */
+};
+
+class pass_variable_tracking_no_opt : public rtl_opt_pass
+{
+public:
+  pass_variable_tracking_no_opt (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_variable_tracking_no_opt, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
+      /* This pass replaces the regular var-tracking pass when it is not
+	 enabled, but only at -O0 (by default, the var-tracking pass is
+	 disabled at -O0 only).  It is useful only when producing debug
+	 information.  */
+      return (optimize == 0
+	      && !flag_var_tracking
+	      && debug_info_level >= DINFO_LEVEL_NORMAL
+	      && (debug_hooks->var_location
+		  != do_nothing_debug_hooks.var_location));
+    }
+
+  virtual unsigned int execute (function *)
+    {
+      return variable_tracking_no_opt_main ();
+    }
+}; // class pass_variable_tracking_no_opt
+
 } // anon namespace
 
 rtl_opt_pass *
@@ -10367,3 +10463,9 @@ make_pass_variable_tracking (gcc::context *ctxt)
 {
   return new pass_variable_tracking (ctxt);
 }
+
+rtl_opt_pass *
+make_pass_variable_tracking_no_opt (gcc::context *ctxt)
+{
+  return new pass_variable_tracking_no_opt (ctxt);
+}
-- 
2.4.5

Reply via email to