[24/24] pdbout: Handle functions with parts in cold section.

Message ID 20210320162652.23346-24-mark@harmstone.com
State New
Headers show
Series
  • [01/24] Add -gcodeview debugging option
Related show

Commit Message

Mark Harmstone March 20, 2021, 4:26 p.m.
---
 gcc/pdbout.c | 226 ++++++++++++++++++++++++++++++++++++++-------------
 gcc/pdbout.h |   2 +
 2 files changed, 170 insertions(+), 58 deletions(-)

-- 
2.26.2

Patch

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 0f5315f7f07..b4528fb79e8 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -71,6 +71,7 @@  static void pdbout_begin_block (unsigned int line ATTRIBUTE_UNUSED,
 				unsigned int blocknum);
 static void pdbout_end_block (unsigned int line ATTRIBUTE_UNUSED,
 			      unsigned int blocknum);
+static void pdbout_new_section (void);
 
 static struct pdb_type *find_type (tree t);
 static char *get_tree_name (tree t);
@@ -145,7 +146,7 @@  const struct gcc_debug_hooks pdb_debug_hooks = {
   pdbout_var_location,
   debug_nothing_tree,		/* inline_entry */
   debug_nothing_tree,		/* size_function */
-  debug_nothing_void,		/* switch_text_section */
+  pdbout_new_section,
   debug_nothing_tree_tree,	/* set_name */
   0,				/* start_end_main_source_file */
   TYPE_SYMTAB_IS_ADDRESS	/* tree_type_symtab_field */
@@ -157,8 +158,8 @@  pdbout_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
 		       unsigned int column ATTRIBUTE_UNUSED,
 		       const char *file ATTRIBUTE_UNUSED)
 {
-  fprintf (asm_out_file, FUNC_BEGIN_LABEL "%u:\n",
-	   current_function_funcdef_no);
+  fprintf (asm_out_file, FUNC_BEGIN_LABEL "%s%u:\n",
+	   in_cold_section_p ? "cold" : "", current_function_funcdef_no);
 }
 
 /* Add label after function end */
@@ -166,7 +167,8 @@  static void
 pdbout_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
 		     const char *file ATTRIBUTE_UNUSED)
 {
-  fprintf (asm_out_file, FUNC_END_LABEL "%u:\n", current_function_funcdef_no);
+  fprintf (asm_out_file, FUNC_END_LABEL "%s%u:\n",
+	   in_cold_section_p ? "cold" : "", current_function_funcdef_no);
 }
 
 /* Output DEFRANGESYMREGISTER or DEFRANGESYMREGISTERREL structure, describing
@@ -464,8 +466,8 @@  pdbout_block (struct pdb_block *block, struct pdb_func *func)
 	}
       else
 	{
-	  fprintf (asm_out_file, "\t.long\t[.Lcvprocstart%u]-[.debug$S]\n",
-		   func->num);
+	  fprintf (asm_out_file, "\t.long\t[.Lcvprocstart%s%u]-[.debug$S]\n",
+		   func->cold ? "cold" : "", func->num);
 	}
 
       fprintf (asm_out_file, "\t.long\t[.Lcvblockend%u]-[.debug$S]\n",
@@ -497,61 +499,72 @@  pdbout_block (struct pdb_block *block, struct pdb_func *func)
 static void
 pdbout_proc32 (struct pdb_func *func)
 {
-  size_t name_len = func->name ? strlen (func->name) : 0;
-  uint16_t len = 40 + name_len, align;
-
-  // start procedure
+  /* Don't output function definition if it contains no lines. This can happen
+   * if the compiler creates a cold function consisting of just ud2. */
 
-  if (len % 4 != 0)
+  if (func->lines)
     {
-      align = 4 - (len % 4);
-      len += 4 - (len % 4);
-    }
-  else
-    align = 0;
+      size_t name_len = func->name ? strlen (func->name) : 0;
+      uint16_t len = 40 + name_len, align;
 
-  fprintf (asm_out_file, ".Lcvprocstart%u:\n", func->num);
-  fprintf (asm_out_file, "\t.short\t0x%x\n",
-	   (uint16_t) (len - sizeof (uint16_t)));	// reclen
-  fprintf (asm_out_file, "\t.short\t0x%x\n",
-	   func->public_flag ? S_GPROC32 : S_LPROC32);
-  fprintf (asm_out_file, "\t.long\t0\n");	// pParent
-  fprintf (asm_out_file, "\t.long\t[.Lcvprocend%u]-[.debug$S]\n",
-	   func->num);	// pEnd
-  fprintf (asm_out_file, "\t.long\t0\n");	// pNext
-  fprintf (asm_out_file,
-	   "\t.long\t[" FUNC_END_LABEL "%u]-[" FUNC_BEGIN_LABEL "%u]\n",
-	   func->num, func->num);	// len
-  fprintf (asm_out_file, "\t.long\t0\n");	// DbgStart
-  fprintf (asm_out_file, "\t.long\t0\n");	// DbgEnd
-  fprintf (asm_out_file, "\t.short\t0x%x\n", func->type ? func->type->id : 0);
-  fprintf (asm_out_file, "\t.short\t0\n");	// padding
 
-  fprintf (asm_out_file, "\t.secrel32\t" FUNC_BEGIN_LABEL "%u\n",
-	   func->num);	// offset
-  fprintf (asm_out_file, "\t.secidx\t" FUNC_BEGIN_LABEL "%u\n",
-	   func->num);	// section
+      // start procedure
 
-  fprintf (asm_out_file, "\t.byte\t0\n");	// flags
+      if (len % 4 != 0)
+	{
+	  align = 4 - (len % 4);
+	  len += 4 - (len % 4);
+	}
+      else
+	align = 0;
 
-  if (func->name)
-    ASM_OUTPUT_ASCII (asm_out_file, func->name, name_len + 1);
-  else
-    fprintf (asm_out_file, "\t.byte\t0\n");
+      fprintf (asm_out_file, ".Lcvprocstart%s%u:\n",
+	      func->cold ? "cold" : "", func->num);
+      fprintf (asm_out_file, "\t.short\t0x%x\n",
+	      (uint16_t) (len - sizeof (uint16_t)));	// reclen
+      fprintf (asm_out_file, "\t.short\t0x%x\n",
+	      func->public_flag ? S_GPROC32 : S_LPROC32);
+      fprintf (asm_out_file, "\t.long\t0\n");	// pParent
+      fprintf (asm_out_file, "\t.long\t[.Lcvprocend%s%u]-[.debug$S]\n",
+	      func->cold ? "cold" : "", func->num);	// pEnd
+      fprintf (asm_out_file, "\t.long\t0\n");	// pNext
+      fprintf (asm_out_file,
+	      "\t.long\t[" FUNC_END_LABEL "%s%u]-[" FUNC_BEGIN_LABEL "%s%u]\n",
+	      func->cold ? "cold" : "", func->num,
+	      func->cold ? "cold" : "", func->num);	// len
+      fprintf (asm_out_file, "\t.long\t0\n");	// DbgStart
+      fprintf (asm_out_file, "\t.long\t0\n");	// DbgEnd
+      fprintf (asm_out_file, "\t.short\t0x%x\n",
+	       func->type ? func->type->id : 0);
+      fprintf (asm_out_file, "\t.short\t0\n");	// padding
 
-  for (unsigned int i = 0; i < align; i++)
-    {
-      fprintf (asm_out_file, "\t.byte\t0\n");
-    }
+      fprintf (asm_out_file, "\t.secrel32\t" FUNC_BEGIN_LABEL "%s%u\n",
+	      func->cold ? "cold" : "", func->num);	// offset
+      fprintf (asm_out_file, "\t.secidx\t" FUNC_BEGIN_LABEL "%s%u\n",
+	      func->cold ? "cold" : "", func->num);	// section
+
+      fprintf (asm_out_file, "\t.byte\t0\n");	// flags
 
-  pdbout_block (&func->block, func);
+      if (func->name)
+	ASM_OUTPUT_ASCII (asm_out_file, func->name, name_len + 1);
+      else
+	fprintf (asm_out_file, "\t.byte\t0\n");
 
-  // end procedure
+      for (unsigned int i = 0; i < align; i++)
+	{
+	  fprintf (asm_out_file, "\t.byte\t0\n");
+	}
 
-  fprintf (asm_out_file, ".Lcvprocend%u:\n", func->num);
+      pdbout_block (&func->block, func);
 
-  fprintf (asm_out_file, "\t.short\t0x2\n");
-  fprintf (asm_out_file, "\t.short\t0x%x\n", S_END);
+      // end procedure
+
+      fprintf (asm_out_file, ".Lcvprocend%s%u:\n",
+	      func->cold ? "cold" : "", func->num);
+
+      fprintf (asm_out_file, "\t.short\t0x2\n");
+      fprintf (asm_out_file, "\t.short\t0x%x\n", S_END);
+    }
 
   while (func->local_vars)
     {
@@ -657,17 +670,32 @@  write_line_numbers ()
 	{
 	  struct pdb_line *l, *last_line;
 	  unsigned int num_entries = 0, source_file, first_entry;
+	  section *sect;
 
 	  source_file = func->lines->source_file;
+	  sect = func->lines->sect;
 
 	  l = last_line = func->lines;
-	  while (l && l->source_file == source_file)
+	  while (l && l->source_file == source_file && l->sect == sect)
 	    {
 	      num_entries++;
 	      last_line = l;
 	      l = l->next;
 	    }
 
+	  /* If pdb_line has a NULL section, it's a sentinel at the end of
+	   * the current section - skip it and move on. */
+	  if (!sect)
+	    {
+	      struct pdb_line *n = func->lines->next;
+
+	      free (func->lines);
+
+	      func->lines = n;
+
+	      continue;
+	    }
+
 	  first_entry = func->lines->entry;
 
 	  fprintf (asm_out_file, "\t.long\t0x%x\n", DEBUG_S_LINES);
@@ -682,17 +710,19 @@  write_line_numbers ()
 
 	  fprintf (asm_out_file, "\t.short\t0\n");	// flags
 
-	  // next section of function is another source file
+	  // next part of function is another source file or section
 	  if (last_line->next)
 	    {
+	      // length
 	      fprintf (asm_out_file, "\t.long\t[.Lline%u]-[.Lline%u]\n",
-		       last_line->next->entry, first_entry);	// length
+		       last_line->next->entry, first_entry);
 	    }
 	  else
 	    {
+	      // length
 	      fprintf (asm_out_file,
-		       "\t.long\t[" FUNC_END_LABEL "%u]-[.Lline%u]\n",
-		       func->num, first_entry);	// length
+		       "\t.long\t[" FUNC_END_LABEL "%s%u]-[.Lline%u]\n",
+		       func->cold ? "cold" : "", func->num, first_entry);
 	    }
 
 	  // file ID (0x18 is size of checksum struct)
@@ -701,7 +731,7 @@  write_line_numbers ()
 	  // length of file block
 	  fprintf (asm_out_file, "\t.long\t0x%x\n", 0xc + (num_entries * 8));
 
-	  while (func->lines && func->lines->source_file == source_file)
+	  while (func->lines && func->lines->source_file == source_file && func->lines->sect == sect)
 	    {
 	      struct pdb_line *n = func->lines->next;
 
@@ -2406,6 +2436,7 @@  pdbout_begin_function (tree func)
   f->lines = f->last_line = NULL;
   f->local_vars = f->last_local_var = NULL;
   f->var_locs = f->last_var_loc = NULL;
+  f->cold = in_cold_section_p;
 
   f->block.next = NULL;
   f->block.parent = NULL;
@@ -4247,6 +4278,7 @@  pdbout_source_line (unsigned int line, unsigned int column ATTRIBUTE_UNUSED,
   ent->line = line;
   ent->entry = num_line_number_entries;
   ent->source_file = source_file;
+  ent->sect = current_function_section ();
 
   if (cur_func->last_line)
     cur_func->last_line->next = ent;
@@ -4254,7 +4286,13 @@  pdbout_source_line (unsigned int line, unsigned int column ATTRIBUTE_UNUSED,
   cur_func->last_line = ent;
 
   if (!cur_func->lines)
-    cur_func->lines = ent;
+    {
+      if (cur_func->cold)
+	fprintf (asm_out_file, FUNC_BEGIN_LABEL "cold%u:\n",
+		 current_function_funcdef_no);
+
+      cur_func->lines = ent;
+    }
 
   fprintf (asm_out_file, ".Lline%u:\n", num_line_number_entries);
 
@@ -5148,6 +5186,9 @@  add_local (const char *name, tree t, struct pdb_type *type, rtx orig_rtl,
   size_t name_len = strlen (name);
   rtx rtl;
 
+  if (cur_func->cold)
+    return;
+
   plv =
     (struct pdb_local_var *) xmalloc (offsetof (struct pdb_local_var, name) +
 				      name_len + 1);
@@ -5286,7 +5327,7 @@  pdbout_var_location (rtx_insn * loc_note)
   tree var;
   struct pdb_var_location *var_loc;
 
-  if (!cur_func)
+  if (!cur_func || cur_func->cold)
     return;
 
   if (!NOTE_P (loc_note))
@@ -5400,3 +5441,72 @@  pdbout_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
 
   cur_block = cur_block->parent;
 }
+
+/* We're switching sections mid-function - this happens when GCC moves part
+ * of a code path to .text.unlikely, such as an if block ending with abort().
+ * Create a new function with ".cold" at the end to accommodate this. */
+static void
+pdbout_new_section (void)
+{
+  struct pdb_line *ent;
+  struct pdb_func *f;
+
+  static const char cold_suf[] = ".cold";
+
+  if (!cur_func)
+    return;
+
+  // add line number for end of current section
+
+  ent = (struct pdb_line *) xmalloc (sizeof (struct pdb_line));
+
+  ent->next = NULL;
+  ent->line = 0;
+  ent->entry = num_line_number_entries;
+  ent->source_file = 0;
+  ent->sect = NULL;
+
+  if (cur_func->last_line)
+    cur_func->last_line->next = ent;
+
+  cur_func->last_line = ent;
+
+  if (!cur_func->lines)
+    cur_func->lines = ent;
+
+  fprintf (asm_out_file, ".Lline%u:\n", num_line_number_entries);
+
+  num_line_number_entries++;
+
+  // end current function
+
+  fprintf (asm_out_file, FUNC_END_LABEL "%u:\n", current_function_funcdef_no);
+
+  // start cold function
+
+  f = (struct pdb_func *) xmalloc (sizeof (struct pdb_func));
+
+  f->next = funcs;
+
+  f->name = (char *) xmalloc (strlen (cur_func->name) + sizeof (cold_suf));
+  strcpy (f->name, cur_func->name);
+  strcat (f->name, cold_suf);
+
+  f->num = current_function_funcdef_no;
+  f->public_flag = cur_func->public_flag;
+  f->type = cur_func->type;
+  f->lines = f->last_line = NULL;
+  f->local_vars = f->last_local_var = NULL;
+  f->var_locs = f->last_var_loc = NULL;
+  f->cold = in_cold_section_p;
+
+  f->block.next = NULL;
+  f->block.parent = NULL;
+  f->block.num = 0;
+  f->block.children = f->block.last_child = NULL;
+
+  funcs = f;
+
+  cur_func = f;
+  cur_block = &f->block;
+}
diff --git a/gcc/pdbout.h b/gcc/pdbout.h
index f1b21fe23a0..7fe0d3312e0 100644
--- a/gcc/pdbout.h
+++ b/gcc/pdbout.h
@@ -75,6 +75,7 @@  struct pdb_line
   unsigned int line;
   unsigned int entry;
   unsigned int source_file;
+  section *sect;
 };
 
 enum pdb_local_var_type
@@ -129,6 +130,7 @@  struct pdb_func
   char *name;
   int num;
   unsigned int public_flag;
+  bool cold;
   struct pdb_type *type;
   struct pdb_line *lines, *last_line;
   struct pdb_local_var *local_vars, *last_local_var;