---
 gcc/pdbout.c | 226 ++++++++++++++++++++++++++++++++++++++-------------
 gcc/pdbout.h |   2 +
 2 files changed, 170 insertions(+), 58 deletions(-)

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;
-- 
2.26.2

Reply via email to