diff mbox series

[committed,OG10] DWARF: late code range fixup

Message ID 75192b9e-1477-61f5-8e7c-3706ecd35e45@codesourcery.com
State New
Headers show
Series [committed,OG10] DWARF: late code range fixup | expand

Commit Message

Andrew Stubbs March 6, 2021, 3:53 p.m. UTC
This patch fixes up the DWARF code ranges for offload debugging, again.

This time it defers the changes until most other DWARF generation has 
occurred, because the previous method was causing ICEs on some testcases.

This patch will be proposed for mainline in stage 1.

Andrew
diff mbox series

Patch

DWARF: late code range fixup

Ensure that the parent DWARF subprograms of offload kernel functions have a
code range, and are therefore not discarded by GDB.  This is only necessary
when the parent function does not actually exist in the final binary, which is
commonly the case within the offload device's binary.

This patch replaces 808bdf1bb29 and fdcb23540a2.  It should be squashed with
those before being posted upstream.

gcc/

	* gcc/dwarf2out.c (notional_parents_list): New file variable.
	(gen_subprogram_die): Record offload kernel functions in
	notional_parents_list.
	(fixup_notional_parents): New function.
	(dwarf2out_finish): Call fixup_notional_parents.
	(dwarf2out_c_finalize): Reset notional_parents_list.

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 1d7cb6273f0..d6796caba3e 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -3427,6 +3427,12 @@  static GTY(()) limbo_die_node *limbo_die_list;
    DW_AT_{,MIPS_}linkage_name once their DECL_ASSEMBLER_NAMEs are set.  */
 static GTY(()) limbo_die_node *deferred_asm_name;
 
+/* A list of DIEs for which we may have to add a notional code range to the
+   parent DIE.  This happens for parents of nested offload kernels, and is
+   necessary because the parents don't exist on the offload target, yet GDB
+   expects parents of real functions to also appear to exist.  */
+static GTY(()) limbo_die_node *notional_parents_list;
+
 struct dwarf_file_hasher : ggc_ptr_hash<dwarf_file_data>
 {
   typedef const char *compare_type;
@@ -23085,34 +23091,25 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
 	  dw_fde_ref fde = fun->fde;
 	  if (fde->dw_fde_begin)
 	    {
-	      dw_attr_node *low = get_AT (subr_die, DW_AT_low_pc);
-	      dw_attr_node *high = get_AT (subr_die, DW_AT_high_pc);
-	      if (low && high)
-		{
-		  /* Replace the existing value, it will have come from
-		     the "omp target entrypoint" case below.  */
-		  free (low->dw_attr_val.v.val_lbl_id);
-		  low->dw_attr_val.v.val_lbl_id = xstrdup (fde->dw_fde_begin);
-		  free (high->dw_attr_val.v.val_lbl_id);
-		  high->dw_attr_val.v.val_lbl_id = xstrdup (fde->dw_fde_end);
-		}
-	      else
-		/* We have already generated the labels.  */
-		add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
-				    fde->dw_fde_end, false);
+	      /* We have already generated the labels.  */
+	      add_AT_low_high_pc (subr_die, fde->dw_fde_begin,
+				  fde->dw_fde_end, false);
 
 	     /* Offload kernel functions are nested within a parent function
 	        that doesn't actually exist within the offload object.  GDB
 		will ignore the function and everything nested within unless
-		we give it a notional code range (the values aren't
-		important, as long as they are valid).  */
+		we give the parent a code range.  We can't do it here because
+		that breaks the case where the parent actually does exist (as
+		it does on the host-side), so we defer the fixup for later.  */
 	     if (lookup_attribute ("omp target entrypoint",
-				   DECL_ATTRIBUTES (decl))
-		 && subr_die->die_parent
-		 && subr_die->die_parent->die_tag == DW_TAG_subprogram
-		 && !get_AT_low_pc (subr_die->die_parent))
-	       add_AT_low_high_pc (subr_die->die_parent, fde->dw_fde_begin,
-				   fde->dw_fde_end, false);
+				   DECL_ATTRIBUTES (decl)))
+	       {
+		 limbo_die_node *node = ggc_cleared_alloc<limbo_die_node> ();
+		 node->die = subr_die;
+		 node->created_for = decl;
+		 node->next = notional_parents_list;
+		 notional_parents_list = node;
+	       }
 	    }
 	  else
 	    {
@@ -31348,6 +31345,37 @@  flush_limbo_die_list (void)
     }
 }
 
+/* Add a code range to the notional parent function (which does not actually
+   exist) so that GDB does not ignore all the child functions.  The actual
+   values do not matter, but need to be valid labels, so we simply copy those
+   from the child function.
+
+   Typically this occurs when we have an offload kernel, where the parent
+   function only exists in the host-side portion of the code.  */
+
+static void
+fixup_notional_parents (void)
+{
+  limbo_die_node *node;
+
+  while ((node = notional_parents_list))
+    {
+      dw_die_ref die = node->die;
+      dw_die_ref parent = die->die_parent;
+      notional_parents_list = node->next;
+
+      if (parent
+	  && parent->die_tag == DW_TAG_subprogram
+	  && !get_AT_low_pc (parent))
+	{
+	  dw_attr_node *low = get_AT (die, DW_AT_low_pc);
+	  dw_attr_node *high = get_AT (die, DW_AT_high_pc);
+
+	  add_AT_low_high_pc (parent, AT_lbl (low), AT_lbl (high), false);
+	}
+    }
+}
+
 /* Reset DIEs so we can output them again.  */
 
 static void
@@ -31378,6 +31406,9 @@  dwarf2out_finish (const char *filename)
   /* Flush out any latecomers to the limbo party.  */
   flush_limbo_die_list ();
 
+  /* Insert an notional parent code ranges.  */
+  fixup_notional_parents ();
+
   if (inline_entry_data_table)
     gcc_assert (inline_entry_data_table->is_empty ());
 
@@ -32394,6 +32425,7 @@  dwarf2out_c_finalize (void)
   single_comp_unit_die = NULL;
   comdat_type_list = NULL;
   limbo_die_list = NULL;
+  notional_parents_list = NULL;
   file_table = NULL;
   decl_die_table = NULL;
   common_block_die_table = NULL;