diff mbox series

Fix DWARF5 .debug_loclist handling with hot/cold partitioning (PR debug/82718)

Message ID 20171026081853.GS14653@tucnak
State New
Headers show
Series Fix DWARF5 .debug_loclist handling with hot/cold partitioning (PR debug/82718) | expand

Commit Message

Jakub Jelinek Oct. 26, 2017, 8:18 a.m. UTC
Hi!

The code in output_loc_list for DWARF5 relies on dw_loc_list_node's
section field accuracy, in particular that nodes with labels in
the hot subsection have one section (label) and nodes with labels
in the cold subsection have another one.  But that is actually not the case,
so we end up with cross-section symbol difference which assembler doesn't
assemble.

The following patch fixes that by making sure that section in the nodes
is accurate.  We already have loc_list->last_before_switch which points
to the last node in the first partition or NULL if either no section
switch was seen (if !crtl->has_bb_partition) or if the first node is after
the section switch (if crtl->has_bb_partition) and use it for the regions
that need to be split among the two.  The patch has lots of reindentation,
so I'm including here also diff -upbd output of the dwarf2out.c changes.
The first if ensures that secname is correct for the first node and the
other changes update it in the loop after processing node equal to
last_before_switch (or, if doing range_across_switch, after emitting
first partition's entry and before emitting second partition's entry).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?


	Jakub
diff mbox series

Patch

diff -upbd here, patch afterwards:
--- gcc/dwarf2out.c.jj	2017-10-23 22:39:27.000000000 +0200
+++ gcc/dwarf2out.c	2017-10-25 21:01:13.237929750 +0200
@@ -16333,21 +16333,31 @@  dw_loc_list (var_loc_list *loc_list, tre
      This means we have to special case the last node, and generate
      a range of [last location start, end of function label].  */
 
+  if (cfun && crtl->has_bb_partition)
+    {
+      bool save_in_cold_section_p = in_cold_section_p;
+      in_cold_section_p = first_function_block_is_cold;
+      if (loc_list->last_before_switch == NULL)
+	in_cold_section_p = !in_cold_section_p;
+      secname = secname_for_decl (decl);
+      in_cold_section_p = save_in_cold_section_p;
+    }
+  else
   secname = secname_for_decl (decl);
 
   for (node = loc_list->first; node; node = node->next)
+    {
+      bool range_across_switch = false;
     if (GET_CODE (node->loc) == EXPR_LIST
 	|| NOTE_VAR_LOCATION_LOC (node->loc) != NULL_RTX)
       {
 	if (GET_CODE (node->loc) == EXPR_LIST)
 	  {
+	      descr = NULL;
 	    /* This requires DW_OP_{,bit_}piece, which is not usable
 	       inside DWARF expressions.  */
-	    if (want_address != 2)
-	      continue;
+	      if (want_address == 2)
 	    descr = dw_sra_loc_expr (decl, node->loc);
-	    if (descr == NULL)
-	      continue;
 	  }
 	else
 	  {
@@ -16357,7 +16367,6 @@  dw_loc_list (var_loc_list *loc_list, tre
 	  }
 	if (descr)
 	  {
-	    bool range_across_switch = false;
 	    /* If section switch happens in between node->label
 	       and node->next->label (or end of function) and
 	       we can't emit it as a single entry list,
@@ -16393,6 +16402,18 @@  dw_loc_list (var_loc_list *loc_list, tre
 		&& strcmp (node->label, endname) == 0)
 	      (*listp)->force = true;
 	    listp = &(*listp)->dw_loc_next;
+	    }
+	}
+
+      if (cfun
+	  && crtl->has_bb_partition
+	  && node == loc_list->last_before_switch)
+	{
+	  bool save_in_cold_section_p = in_cold_section_p;
+	  in_cold_section_p = !first_function_block_is_cold;
+	  secname = secname_for_decl (decl);
+	  in_cold_section_p = save_in_cold_section_p;
+	}
 
 	    if (range_across_switch)
 	      {
@@ -16412,13 +16433,11 @@  dw_loc_list (var_loc_list *loc_list, tre
 		  endname = node->next->label;
 		else
 		  endname = cfun->fde->dw_fde_second_end;
-		*listp = new_loc_list (descr,
-				       cfun->fde->dw_fde_second_begin,
+	  *listp = new_loc_list (descr, cfun->fde->dw_fde_second_begin,
 				       endname, secname);
 		listp = &(*listp)->dw_loc_next;
 	      }
 	  }
-      }
 
   /* Try to avoid the overhead of a location list emitting a location
      expression instead, but only if we didn't have more than one



2017-10-26  Jakub Jelinek  <jakub@redhat.com>

	PR debug/82718
	* dwarf2out.c (dw_loc_list): If crtl->has_bb_partition, temporarily
	set in_cold_section_p to the partition containing loc_list->first.
	When seeing loc_list->last_before_switch node, update secname and
	perform range_across_switch second partition handling only after that.

	* gcc.dg/debug/dwarf2/pr82718.c: New test.

--- gcc/dwarf2out.c.jj	2017-10-23 22:39:27.000000000 +0200
+++ gcc/dwarf2out.c	2017-10-25 21:01:13.237929750 +0200
@@ -16333,92 +16333,111 @@  dw_loc_list (var_loc_list *loc_list, tre
      This means we have to special case the last node, and generate
      a range of [last location start, end of function label].  */
 
-  secname = secname_for_decl (decl);
+  if (cfun && crtl->has_bb_partition)
+    {
+      bool save_in_cold_section_p = in_cold_section_p;
+      in_cold_section_p = first_function_block_is_cold;
+      if (loc_list->last_before_switch == NULL)
+	in_cold_section_p = !in_cold_section_p;
+      secname = secname_for_decl (decl);
+      in_cold_section_p = save_in_cold_section_p;
+    }
+  else
+    secname = secname_for_decl (decl);
 
   for (node = loc_list->first; node; node = node->next)
-    if (GET_CODE (node->loc) == EXPR_LIST
-	|| NOTE_VAR_LOCATION_LOC (node->loc) != NULL_RTX)
-      {
-	if (GET_CODE (node->loc) == EXPR_LIST)
-	  {
-	    /* This requires DW_OP_{,bit_}piece, which is not usable
-	       inside DWARF expressions.  */
-	    if (want_address != 2)
-	      continue;
+    {
+      bool range_across_switch = false;
+      if (GET_CODE (node->loc) == EXPR_LIST
+	  || NOTE_VAR_LOCATION_LOC (node->loc) != NULL_RTX)
+	{
+	  if (GET_CODE (node->loc) == EXPR_LIST)
+	    {
+	      descr = NULL;
+	      /* This requires DW_OP_{,bit_}piece, which is not usable
+		 inside DWARF expressions.  */
+	      if (want_address == 2)
+		descr = dw_sra_loc_expr (decl, node->loc);
+	    }
+	  else
+	    {
+	      initialized = NOTE_VAR_LOCATION_STATUS (node->loc);
+	      varloc = NOTE_VAR_LOCATION (node->loc);
+	      descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
+	    }
+	  if (descr)
+	    {
+	      /* If section switch happens in between node->label
+		 and node->next->label (or end of function) and
+		 we can't emit it as a single entry list,
+		 emit two ranges, first one ending at the end
+		 of first partition and second one starting at the
+		 beginning of second partition.  */
+	      if (node == loc_list->last_before_switch
+		  && (node != loc_list->first || loc_list->first->next)
+		  && current_function_decl)
+		{
+		  endname = cfun->fde->dw_fde_end;
+		  range_across_switch = true;
+		}
+	      /* The variable has a location between NODE->LABEL and
+		 NODE->NEXT->LABEL.  */
+	      else if (node->next)
+		endname = node->next->label;
+	      /* If the variable has a location at the last label
+		 it keeps its location until the end of function.  */
+	      else if (!current_function_decl)
+		endname = text_end_label;
+	      else
+		{
+		  ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+					       current_function_funcdef_no);
+		  endname = ggc_strdup (label_id);
+		}
+
+	      *listp = new_loc_list (descr, node->label, endname, secname);
+	      if (TREE_CODE (decl) == PARM_DECL
+		  && node == loc_list->first
+		  && NOTE_P (node->loc)
+		  && strcmp (node->label, endname) == 0)
+		(*listp)->force = true;
+	      listp = &(*listp)->dw_loc_next;
+	    }
+	}
+
+      if (cfun
+	  && crtl->has_bb_partition
+	  && node == loc_list->last_before_switch)
+	{
+	  bool save_in_cold_section_p = in_cold_section_p;
+	  in_cold_section_p = !first_function_block_is_cold;
+	  secname = secname_for_decl (decl);
+	  in_cold_section_p = save_in_cold_section_p;
+	}
+
+      if (range_across_switch)
+	{
+	  if (GET_CODE (node->loc) == EXPR_LIST)
 	    descr = dw_sra_loc_expr (decl, node->loc);
-	    if (descr == NULL)
-	      continue;
-	  }
-	else
-	  {
-	    initialized = NOTE_VAR_LOCATION_STATUS (node->loc);
-	    varloc = NOTE_VAR_LOCATION (node->loc);
-	    descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
-	  }
-	if (descr)
-	  {
-	    bool range_across_switch = false;
-	    /* If section switch happens in between node->label
-	       and node->next->label (or end of function) and
-	       we can't emit it as a single entry list,
-	       emit two ranges, first one ending at the end
-	       of first partition and second one starting at the
-	       beginning of second partition.  */
-	    if (node == loc_list->last_before_switch
-		&& (node != loc_list->first || loc_list->first->next)
-		&& current_function_decl)
-	      {
-		endname = cfun->fde->dw_fde_end;
-		range_across_switch = true;
-	      }
-	    /* The variable has a location between NODE->LABEL and
-	       NODE->NEXT->LABEL.  */
-	    else if (node->next)
-	      endname = node->next->label;
-	    /* If the variable has a location at the last label
-	       it keeps its location until the end of function.  */
-	    else if (!current_function_decl)
-	      endname = text_end_label;
-	    else
-	      {
-		ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
-					     current_function_funcdef_no);
-		endname = ggc_strdup (label_id);
-	      }
-
-	    *listp = new_loc_list (descr, node->label, endname, secname);
-	    if (TREE_CODE (decl) == PARM_DECL
-		&& node == loc_list->first
-		&& NOTE_P (node->loc)
-		&& strcmp (node->label, endname) == 0)
-	      (*listp)->force = true;
-	    listp = &(*listp)->dw_loc_next;
-
-	    if (range_across_switch)
-	      {
-		if (GET_CODE (node->loc) == EXPR_LIST)
-		  descr = dw_sra_loc_expr (decl, node->loc);
-		else
-		  {
-		    initialized = NOTE_VAR_LOCATION_STATUS (node->loc);
-		    varloc = NOTE_VAR_LOCATION (node->loc);
-		    descr = dw_loc_list_1 (decl, varloc, want_address,
-					   initialized);
-		  }
-		gcc_assert (descr);
-		/* The variable has a location between NODE->LABEL and
-		   NODE->NEXT->LABEL.  */
-		if (node->next)
-		  endname = node->next->label;
-		else
-		  endname = cfun->fde->dw_fde_second_end;
-		*listp = new_loc_list (descr,
-				       cfun->fde->dw_fde_second_begin,
-				       endname, secname);
-		listp = &(*listp)->dw_loc_next;
-	      }
-	  }
-      }
+	  else
+	    {
+	      initialized = NOTE_VAR_LOCATION_STATUS (node->loc);
+	      varloc = NOTE_VAR_LOCATION (node->loc);
+	      descr = dw_loc_list_1 (decl, varloc, want_address,
+				     initialized);
+	    }
+	  gcc_assert (descr);
+	  /* The variable has a location between NODE->LABEL and
+	     NODE->NEXT->LABEL.  */
+	  if (node->next)
+	    endname = node->next->label;
+	  else
+	    endname = cfun->fde->dw_fde_second_end;
+	  *listp = new_loc_list (descr, cfun->fde->dw_fde_second_begin,
+				 endname, secname);
+	  listp = &(*listp)->dw_loc_next;
+	}
+    }
 
   /* Try to avoid the overhead of a location list emitting a location
      expression instead, but only if we didn't have more than one
--- gcc/testsuite/gcc.dg/debug/dwarf2/pr82718.c.jj	2017-10-25 21:10:53.324920386 +0200
+++ gcc/testsuite/gcc.dg/debug/dwarf2/pr82718.c	2017-10-25 21:10:25.000000000 +0200
@@ -0,0 +1,41 @@ 
+/* PR debug/82718 */
+/* { dg-do assemble } */
+/* { dg-options "-O2 -gdwarf-5" } */
+
+extern int e;
+extern long foo (int, void *, unsigned long, unsigned long);
+struct S
+{
+  int f;
+  unsigned long t, s;
+};
+
+static inline long
+bv (int x, void *y, unsigned long z, unsigned long w)
+{
+  long a = 0;
+  do
+    {
+      long g;
+      do
+	g = (long int) (foo (x, y + a, z - a, w + a));
+      while (g == -1L && e == 9959);
+      if (g <= 0)
+	return g < 0 ? g : a;
+      a += g;
+    }
+  while ((unsigned long) a < z);
+  return a;
+}
+
+const char *
+baz (struct S *x)
+{
+  unsigned long h = 8;
+  char *j = 0;
+  unsigned long z = x->f;
+  if (__builtin_expect (!!((unsigned long) bv (x->f, j, z, x->t + h + 10) != z), 0))
+    return 0;
+  x->s = z;
+  return j;
+}