diff mbox series

[v2] Add line debug info for virtual thunks [PR97937]

Message ID AM0PR0602MB3410E6913B94DFC7759F30DDE4A90@AM0PR0602MB3410.eurprd06.prod.outlook.com
State New
Headers show
Series [v2] Add line debug info for virtual thunks [PR97937] | expand

Commit Message

Bernd Edlinger Jan. 13, 2021, 2:59 p.m. UTC
Hi,

this is a new improved version of my patch.
The previous patch had two defects:
It failed with -ffunction-section.  Although
the line info was emitted, that was not working
since the debug_ranges did not contain the
thunk.
And secondly it failed to address the case of
functions without any source line information.

The new pattch addresses both cases, of DECL_IGNORED_P
functions:

In the case of virtual thunks we emit the line
number from the declaration.
Other than the previous version this patch
also explicitly adds the virtual thunk to the
debug_ranges and debug_aranges.  If that is not
done, the debugger does not recognize the line
table for these functions.

But if that location info is unavailable,
the function is explicitly removed from the
debug_ranges and debug_aranges.  That has
the same effect as a theoretical .noloc assembler
directive.


Bootstrapped and reg-tested on x86_64-pc-linux-gnu.
Is it OK for trunk?


Thanks
Bernd.

Comments

Bernd Edlinger Jan. 20, 2021, 9:09 a.m. UTC | #1
Ping?

The patch was posted before Stage 4 started:
https://gcc.gnu.org/pipermail/gcc-patches/2021-January/563391.html

Thanks
Bernd.


On 1/13/21 3:59 PM, Bernd Edlinger wrote:
> Hi,
> 
> this is a new improved version of my patch.
> The previous patch had two defects:
> It failed with -ffunction-section.  Although
> the line info was emitted, that was not working
> since the debug_ranges did not contain the
> thunk.
> And secondly it failed to address the case of
> functions without any source line information.
> 
> The new pattch addresses both cases, of DECL_IGNORED_P
> functions:
> 
> In the case of virtual thunks we emit the line
> number from the declaration.
> Other than the previous version this patch
> also explicitly adds the virtual thunk to the
> debug_ranges and debug_aranges.  If that is not
> done, the debugger does not recognize the line
> table for these functions.
> 
> But if that location info is unavailable,
> the function is explicitly removed from the
> debug_ranges and debug_aranges.  That has
> the same effect as a theoretical .noloc assembler
> directive.
> 
> 
> Bootstrapped and reg-tested on x86_64-pc-linux-gnu.
> Is it OK for trunk?
> 
> 
> Thanks
> Bernd.
>
Bernd Edlinger April 29, 2021, 4:27 p.m. UTC | #2
Hi!


I've re-based and re-tested this patch on current trunk.
Otherwise the patch is unchanged, from the previous v2 version.

This patch is fixing two issues with functions where we
do not have proper debug info:

1. Functions without line-numbers at all, are excluded from
the CU's address range in the debug info.  This makes the
debugger not display any line numbers but instead the debugger
steps into assembler.

2. Functions with a declaration line number show this line
number instead of a completely unrelated line-number from a
different function that was emitted before the current one.

So, since we are again in stage 1:
Is it OK for trunk?


Thanks
Bernd.


On 1/13/21 3:59 PM, Bernd Edlinger wrote:
> Hi,
> 
> this is a new improved version of my patch.
> The previous patch had two defects:
> It failed with -ffunction-section.  Although
> the line info was emitted, that was not working
> since the debug_ranges did not contain the
> thunk.
> And secondly it failed to address the case of
> functions without any source line information.
> 
> The new pattch addresses both cases, of DECL_IGNORED_P
> functions:
> 
> In the case of virtual thunks we emit the line
> number from the declaration.
> Other than the previous version this patch
> also explicitly adds the virtual thunk to the
> debug_ranges and debug_aranges.  If that is not
> done, the debugger does not recognize the line
> table for these functions.
> 
> But if that location info is unavailable,
> the function is explicitly removed from the
> debug_ranges and debug_aranges.  That has
> the same effect as a theoretical .noloc assembler
> directive.
> 
> 
> Bootstrapped and reg-tested on x86_64-pc-linux-gnu.
> Is it OK for trunk?
> 
> 
> Thanks
> Bernd.
>
Richard Biener May 3, 2021, 11:44 a.m. UTC | #3
On Thu, 29 Apr 2021, Bernd Edlinger wrote:

> Hi!
> 
> 
> I've re-based and re-tested this patch on current trunk.
> Otherwise the patch is unchanged, from the previous v2 version.
> 
> This patch is fixing two issues with functions where we
> do not have proper debug info:
> 
> 1. Functions without line-numbers at all, are excluded from
> the CU's address range in the debug info.  This makes the
> debugger not display any line numbers but instead the debugger
> steps into assembler.
> 
> 2. Functions with a declaration line number show this line
> number instead of a completely unrelated line-number from a
> different function that was emitted before the current one.
> 
> So, since we are again in stage 1:
> Is it OK for trunk?

Overall it looks good to me but I'm not familiar with the code
and thus maybe unable to spot obvious downsides.

So - OK unless you hear concerns by others in a day or two.

Thanks,
Richard.

> 
> Thanks
> Bernd.
> 
> 
> On 1/13/21 3:59 PM, Bernd Edlinger wrote:
> > Hi,
> > 
> > this is a new improved version of my patch.
> > The previous patch had two defects:
> > It failed with -ffunction-section.  Although
> > the line info was emitted, that was not working
> > since the debug_ranges did not contain the
> > thunk.
> > And secondly it failed to address the case of
> > functions without any source line information.
> > 
> > The new pattch addresses both cases, of DECL_IGNORED_P
> > functions:
> > 
> > In the case of virtual thunks we emit the line
> > number from the declaration.
> > Other than the previous version this patch
> > also explicitly adds the virtual thunk to the
> > debug_ranges and debug_aranges.  If that is not
> > done, the debugger does not recognize the line
> > table for these functions.
> > 
> > But if that location info is unavailable,
> > the function is explicitly removed from the
> > debug_ranges and debug_aranges.  That has
> > the same effect as a theoretical .noloc assembler
> > directive.
> > 
> > 
> > Bootstrapped and reg-tested on x86_64-pc-linux-gnu.
> > Is it OK for trunk?
> > 
> > 
> > Thanks
> > Bernd.
> > 
>
diff mbox series

Patch

From feffb6731523e3a77566c2a5f541c6b90e1ffb19 Mon Sep 17 00:00:00 2001
From: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date: Tue, 12 Jan 2021 16:27:53 +0100
Subject: [PATCH] Add line debug info for virtual thunks

There is no debug info when the DECL_IGNORED_P flag
is set.  But sometimes we have the line info of the
function decl, as in the case of on virtual thunks.
So instead of no line info at all, we emit at least
the location of the function decl.
On the other side, there are DECL_IGNORED_P functions
which do not have any source line info at all.
Remove those from the debug_range info, to make it
clear for the debugger that the line info for these
functions is invalid.  This has the effect that the
debugger will not step into the function without
debug info.

2021-01-13  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	PR ipa/97937
	* debug.h (gcc_debug_hooks): Add set_ignored_loc function pointer.
	* dwarf2out.h (dw_fde_node::ignored_debug): New data item.
	* dbxout.c (dbx_debug_hooks, xcoff_debug_hooks): Add dummy
	set_ignored_loc callbacks.
	* debug.c (do_nothing_debug_hooks): Likewise.
	* vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
	* dwarf2out.c (text_section_used, cold_text_section_used): Remove.
	(in_text_section_p, last_text_label, last_cold_label,
	switch_text_ranges, switch_cold_ranges): New data items.
	(dwarf2out_note_section_used): Remove.
	(dwarf2out_begin_prologue): Set fde->ignored_debug and
	in_text_section_p.
	(mark_ignored_debug_section): New helper function.
	(dwarf2out_end_epilogue, dwarf2out_switch_text_section): Call
	mark_ignored_debug_section.
	(dwarf2_debug_hooks): Use dwarf2out_set_ignored_loc.
	(dwarf2_lineno_debug_hooks): Use dummy for set_ignored_loc.
	(size_of_aranges): Adjust formula for multi-part text ranges size.
	(output_aranges): Output multi-part text ranges.
	(dwarf2out_set_ignored_loc): New callback function.
	(dwarf2out_finish): Output multi-part text ranges.
	(dwarf2out_c_finalize): Clear new data items.
	* final.c (final_start_function_1): Call set_ignored_loc callback.
	(final_scan_insn_1): Likewise.
	* ggc-page.c (gt_ggc_mx): New helper function.
	* stringpool.c (gt_pch_nx): Likewise.
---
 gcc/dbxout.c     |   2 +
 gcc/debug.c      |   1 +
 gcc/debug.h      |   4 +
 gcc/dwarf2out.c  | 244 +++++++++++++++++++++++++++++++++++++++++++------------
 gcc/dwarf2out.h  |   2 +
 gcc/final.c      |   8 ++
 gcc/ggc-page.c   |   6 ++
 gcc/stringpool.c |   6 ++
 gcc/vmsdbgout.c  |   1 +
 9 files changed, 224 insertions(+), 50 deletions(-)

diff --git a/gcc/dbxout.c b/gcc/dbxout.c
index 70b635c..d20527b 100644
--- a/gcc/dbxout.c
+++ b/gcc/dbxout.c
@@ -362,6 +362,7 @@  const struct gcc_debug_hooks dbx_debug_hooks =
   dbxout_end_block,
   debug_true_const_tree,	         /* ignore_block */
   dbxout_source_line,		         /* source_line */
+  debug_nothing_int_int_charstar,	 /* set_ignored_loc */
   dbxout_begin_prologue,	         /* begin_prologue */
   debug_nothing_int_charstar,	         /* end_prologue */
   debug_nothing_int_charstar,	         /* begin_epilogue */
@@ -409,6 +410,7 @@  const struct gcc_debug_hooks xcoff_debug_hooks =
   xcoffout_end_block,
   debug_true_const_tree,	         /* ignore_block */
   xcoffout_source_line,
+  debug_nothing_int_int_charstar,	 /* set_ignored_loc */
   xcoffout_begin_prologue,	         /* begin_prologue */
   debug_nothing_int_charstar,	         /* end_prologue */
   debug_nothing_int_charstar,	         /* begin_epilogue */
diff --git a/gcc/debug.c b/gcc/debug.c
index 0a7fcfa..39add0d 100644
--- a/gcc/debug.c
+++ b/gcc/debug.c
@@ -36,6 +36,7 @@  const struct gcc_debug_hooks do_nothing_debug_hooks =
   debug_nothing_int_int,	         /* end_block */
   debug_true_const_tree,	         /* ignore_block */
   debug_nothing_int_int_charstar_int_bool, /* source_line */
+  debug_nothing_int_int_charstar,	 /* set_ignored_loc */
   debug_nothing_int_int_charstar,	 /* begin_prologue */
   debug_nothing_int_charstar,	         /* end_prologue */
   debug_nothing_int_charstar,	         /* begin_epilogue */
diff --git a/gcc/debug.h b/gcc/debug.h
index 67e5267..b456e01 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -69,6 +69,10 @@  struct gcc_debug_hooks
   void (* source_line) (unsigned int line, unsigned int column,
 			const char *file, int discriminator, bool is_stmt);
 
+  /* Record a source file location for a DECL_IGNORED_P function.  */
+  void (* set_ignored_loc) (unsigned int line, unsigned int column,
+			    const char *file);
+
   /* Called at start of prologue code.  LINE is the first line in the
      function.  */
   void (* begin_prologue) (unsigned int line, unsigned int column,
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 8b6890a..c3bc020 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -258,13 +258,21 @@  static GTY(()) int dw2_string_counter;
 /* True if the compilation unit places functions in more than one section.  */
 static GTY(()) bool have_multiple_function_sections = false;
 
-/* Whether the default text and cold text sections have been used at all.  */
-static GTY(()) bool text_section_used = false;
-static GTY(()) bool cold_text_section_used = false;
-
 /* The default cold text section.  */
 static GTY(()) section *cold_text_section;
 
+/* True if currently in text section.  */
+static GTY(()) bool in_text_section_p = false;
+
+/* Last debug-on location in corresponding section.  */
+static GTY(()) const char *last_text_label;
+static GTY(()) const char *last_cold_label;
+
+/* Mark debug-on/off locations per section.
+   NULL means the section is not used at all.  */
+static GTY(()) vec<const char *, va_gc> *switch_text_ranges;
+static GTY(()) vec<const char *, va_gc> *switch_cold_ranges;
+
 /* The DIE for C++14 'auto' in a function return type.  */
 static GTY(()) dw_die_ref auto_die;
 
@@ -274,7 +282,6 @@  static GTY(()) dw_die_ref decltype_auto_die;
 /* Forward declarations for functions defined in this file.  */
 
 static void output_call_frame_info (int);
-static void dwarf2out_note_section_used (void);
 
 /* Personality decl of current unit.  Used only when assembler does not support
    personality CFI.  */
@@ -1107,6 +1114,8 @@  dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
   fde->dw_fde_current_label = dup_label;
   fde->in_std_section = (fnsec == text_section
 			 || (cold_text_section && fnsec == cold_text_section));
+  fde->ignored_debug = DECL_IGNORED_P (current_function_decl);
+  in_text_section_p = fnsec == text_section;
 
   /* We only want to output line number information for the genuine dwarf2
      prologue case, not the eh frame case.  */
@@ -1174,6 +1183,59 @@  dwarf2out_vms_begin_epilogue (unsigned int line ATTRIBUTE_UNUSED,
   fde->dw_fde_vms_begin_epilogue = xstrdup (label);
 }
 
+/* Mark the ranges of non-debug subsections in the std text sections.  */
+
+static void
+mark_ignored_debug_section (dw_fde_ref fde, bool second)
+{
+  bool std_section;
+  const char *begin_label, *end_label;
+  const char **last_end_label;
+  vec<const char *, va_gc> **switch_ranges;
+
+  if (second)
+    {
+      std_section = fde->second_in_std_section;
+      begin_label = fde->dw_fde_second_begin;
+      end_label   = fde->dw_fde_second_end;
+    }
+  else
+    {
+      std_section = fde->in_std_section;
+      begin_label = fde->dw_fde_begin;
+      end_label   = fde->dw_fde_end;
+    }
+
+  if (!std_section)
+    return;
+
+  if (in_text_section_p)
+    {
+      last_end_label = &last_text_label;
+      switch_ranges  = &switch_text_ranges;
+    }
+  else
+    {
+      last_end_label = &last_cold_label;
+      switch_ranges  = &switch_cold_ranges;
+    }
+
+  if (fde->ignored_debug)
+    {
+      if (*switch_ranges && !(vec_safe_length (*switch_ranges) & 1))
+	vec_safe_push (*switch_ranges, *last_end_label);
+    }
+  else
+    {
+      *last_end_label = end_label;
+
+      if (!*switch_ranges)
+	vec_alloc (*switch_ranges, 16);
+      else if (vec_safe_length (*switch_ranges) & 1)
+	vec_safe_push (*switch_ranges, begin_label);
+    }
+}
+
 /* Output a marker (i.e. a label) for the absolute end of the generated code
    for a function definition.  This gets called *after* the epilogue code has
    been generated.  */
@@ -1200,6 +1262,8 @@  dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
   gcc_assert (fde != NULL);
   if (fde->dw_fde_second_begin == NULL)
     fde->dw_fde_end = xstrdup (label);
+
+  mark_ignored_debug_section (fde, fde->dw_fde_second_begin != NULL);
 }
 
 void
@@ -1214,18 +1278,6 @@  dwarf2out_frame_finish (void)
     output_call_frame_info (1);
 }
 
-/* Note that the current function section is being used for code.  */
-
-static void
-dwarf2out_note_section_used (void)
-{
-  section *sec = current_function_section ();
-  if (sec == text_section)
-    text_section_used = true;
-  else if (sec == cold_text_section)
-    cold_text_section_used = true;
-}
-
 static void var_location_switch_text_section (void);
 static void set_cur_line_info_table (section *);
 
@@ -1254,13 +1306,11 @@  dwarf2out_switch_text_section (void)
     }
   have_multiple_function_sections = true;
 
-  /* There is no need to mark used sections when not debugging.  */
-  if (cold_text_section != NULL)
-    dwarf2out_note_section_used ();
-
   if (dwarf2out_do_cfi_asm ())
     fprintf (asm_out_file, "\t.cfi_endproc\n");
 
+  mark_ignored_debug_section (fde, false);
+
   /* Now do the real section switch.  */
   sect = current_function_section ();
   switch_to_section (sect);
@@ -1268,6 +1318,7 @@  dwarf2out_switch_text_section (void)
   fde->second_in_std_section
     = (sect == text_section
        || (cold_text_section && sect == cold_text_section));
+  in_text_section_p = sect == text_section;
 
   if (dwarf2out_do_cfi_asm ())
     dwarf2out_do_cfi_startproc (true);
@@ -2800,6 +2851,7 @@  static void dwarf2out_function_decl (tree);
 static void dwarf2out_begin_block (unsigned, unsigned);
 static void dwarf2out_end_block (unsigned, unsigned);
 static bool dwarf2out_ignore_block (const_tree);
+static void dwarf2out_set_ignored_loc (unsigned, unsigned, const char *);
 static void dwarf2out_early_global_decl (tree);
 static void dwarf2out_late_global_decl (tree);
 static void dwarf2out_type_decl (tree, int);
@@ -2835,6 +2887,7 @@  const struct gcc_debug_hooks dwarf2_debug_hooks =
   dwarf2out_end_block,
   dwarf2out_ignore_block,
   dwarf2out_source_line,
+  dwarf2out_set_ignored_loc,
   dwarf2out_begin_prologue,
 #if VMS_DEBUGGING_INFO
   dwarf2out_vms_end_prologue,
@@ -2884,6 +2937,7 @@  const struct gcc_debug_hooks dwarf2_lineno_debug_hooks =
   debug_nothing_int_int,	         /* end_block */
   debug_true_const_tree,	         /* ignore_block */
   dwarf2out_source_line,		 /* source_line */
+  debug_nothing_int_int_charstar,	 /* set_ignored_loc */
   debug_nothing_int_int_charstar,	 /* begin_prologue */
   debug_nothing_int_charstar,	         /* end_prologue */
   debug_nothing_int_charstar,	         /* begin_epilogue */
@@ -9740,10 +9794,12 @@  size_of_aranges (void)
   size = DWARF_ARANGES_HEADER_SIZE;
 
   /* Count the address/length pair for this compilation unit.  */
-  if (text_section_used)
-    size += 2 * DWARF2_ADDR_SIZE;
-  if (cold_text_section_used)
-    size += 2 * DWARF2_ADDR_SIZE;
+  if (switch_text_ranges)
+    size += 2 * DWARF2_ADDR_SIZE
+	    * (vec_safe_length (switch_text_ranges) / 2 + 1);
+  if (switch_cold_ranges)
+    size += 2 * DWARF2_ADDR_SIZE
+	    * (vec_safe_length (switch_cold_ranges) / 2 + 1);
   if (have_multiple_function_sections)
     {
       unsigned fde_idx;
@@ -9751,7 +9807,7 @@  size_of_aranges (void)
 
       FOR_EACH_VEC_ELT (*fde_vec, fde_idx, fde)
 	{
-	  if (DECL_IGNORED_P (fde->decl))
+	  if (fde->ignored_debug)
 	    continue;
 	  if (!fde->in_std_section)
 	    size += 2 * DWARF2_ADDR_SIZE;
@@ -11683,18 +11739,52 @@  output_aranges (void)
      the address may end up as 0 if the section is discarded by ld
      --gc-sections, leaving an invalid (0, 0) entry that can be
      confused with the terminator.  */
-  if (text_section_used)
+  if (switch_text_ranges)
     {
-      dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_section_label, "Address");
-      dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
-			    text_section_label, "Length");
+      const char *prev_loc = text_section_label;
+      const char *loc;
+      unsigned idx;
+
+      FOR_EACH_VEC_ELT (*switch_text_ranges, idx, loc)
+	if (prev_loc)
+	  {
+	    dw2_asm_output_addr (DWARF2_ADDR_SIZE, prev_loc, "Address");
+	    dw2_asm_output_delta (DWARF2_ADDR_SIZE, loc, prev_loc, "Length");
+	    prev_loc = NULL;
+	  }
+	else
+	  prev_loc = loc;
+
+      if (prev_loc)
+	{
+	  dw2_asm_output_addr (DWARF2_ADDR_SIZE, prev_loc, "Address");
+	  dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
+				prev_loc, "Length");
+	}
     }
-  if (cold_text_section_used)
+
+  if (switch_cold_ranges)
     {
-      dw2_asm_output_addr (DWARF2_ADDR_SIZE, cold_text_section_label,
-			   "Address");
-      dw2_asm_output_delta (DWARF2_ADDR_SIZE, cold_end_label,
-			    cold_text_section_label, "Length");
+      const char *prev_loc = cold_text_section_label;
+      const char *loc;
+      unsigned idx;
+
+      FOR_EACH_VEC_ELT (*switch_cold_ranges, idx, loc)
+	if (prev_loc)
+	  {
+	    dw2_asm_output_addr (DWARF2_ADDR_SIZE, prev_loc, "Address");
+	    dw2_asm_output_delta (DWARF2_ADDR_SIZE, loc, prev_loc, "Length");
+	    prev_loc = NULL;
+	  }
+	else
+	  prev_loc = loc;
+
+      if (prev_loc)
+	{
+	  dw2_asm_output_addr (DWARF2_ADDR_SIZE, prev_loc, "Address");
+	  dw2_asm_output_delta (DWARF2_ADDR_SIZE, cold_end_label,
+				prev_loc, "Length");
+	}
     }
 
   if (have_multiple_function_sections)
@@ -11704,7 +11794,7 @@  output_aranges (void)
 
       FOR_EACH_VEC_ELT (*fde_vec, fde_idx, fde)
 	{
-	  if (DECL_IGNORED_P (fde->decl))
+	  if (fde->ignored_debug)
 	    continue;
 	  if (!fde->in_std_section)
 	    {
@@ -27777,7 +27867,6 @@  dwarf2out_begin_function (tree fun)
       switch_to_section (sec);
     }
 
-  dwarf2out_note_section_used ();
   call_site_count = 0;
   tail_call_site_count = 0;
 
@@ -28080,6 +28169,20 @@  dwarf2out_source_line (unsigned int line, unsigned int column,
   table->in_use = true;
 }
 
+/* Record a source file location for a DECL_IGNORED_P function.  */
+
+static void
+dwarf2out_set_ignored_loc (unsigned int line, unsigned int column,
+			   const char *filename)
+{
+  dw_fde_ref fde = cfun->fde;
+
+  fde->ignored_debug = false;
+  set_cur_line_info_table (function_section (fde->decl));
+
+  dwarf2out_source_line (line, column, filename, 0, true);
+}
+
 /* Record the beginning of a new source file.  */
 
 static void
@@ -31447,30 +31550,68 @@  dwarf2out_finish (const char *filename)
 
   /* We can only use the low/high_pc attributes if all of the code was
      in .text.  */
-  if (!have_multiple_function_sections 
+  if ((!have_multiple_function_sections
+       && vec_safe_length (switch_text_ranges) < 2)
       || (dwarf_version < 3 && dwarf_strict))
     {
+      const char *end_label = text_end_label;
+      if (vec_safe_length (switch_text_ranges) == 1)
+	end_label = (*switch_text_ranges)[0];
       /* Don't add if the CU has no associated code.  */
-      if (text_section_used)
-        add_AT_low_high_pc (main_comp_unit_die, text_section_label,
-                            text_end_label, true);
+      if (switch_text_ranges)
+	add_AT_low_high_pc (main_comp_unit_die, text_section_label,
+			    end_label, true);
     }
   else
     {
       unsigned fde_idx;
       dw_fde_ref fde;
       bool range_list_added = false;
+      if (switch_text_ranges)
+	{
+	  const char *prev_loc = text_section_label;
+	  const char *loc;
+	  unsigned idx;
+
+	  FOR_EACH_VEC_ELT (*switch_text_ranges, idx, loc)
+	    if (prev_loc)
+	      {
+		add_ranges_by_labels (main_comp_unit_die, prev_loc,
+				      loc, &range_list_added, true);
+		prev_loc = NULL;
+	      }
+	    else
+	      prev_loc = loc;
 
-      if (text_section_used)
-        add_ranges_by_labels (main_comp_unit_die, text_section_label,
-                              text_end_label, &range_list_added, true);
-      if (cold_text_section_used)
-        add_ranges_by_labels (main_comp_unit_die, cold_text_section_label,
-                              cold_end_label, &range_list_added, true);
+	  if (prev_loc)
+	    add_ranges_by_labels (main_comp_unit_die, prev_loc,
+				  text_end_label, &range_list_added, true);
+	}
+
+      if (switch_cold_ranges)
+	{
+	  const char *prev_loc = cold_text_section_label;
+	  const char *loc;
+	  unsigned idx;
+
+	  FOR_EACH_VEC_ELT (*switch_cold_ranges, idx, loc)
+	    if (prev_loc)
+	      {
+		add_ranges_by_labels (main_comp_unit_die, prev_loc,
+				      loc, &range_list_added, true);
+		prev_loc = NULL;
+	      }
+	    else
+	      prev_loc = loc;
+
+	  if (prev_loc)
+	    add_ranges_by_labels (main_comp_unit_die, prev_loc,
+				  cold_end_label, &range_list_added, true);
+	}
 
       FOR_EACH_VEC_ELT (*fde_vec, fde_idx, fde)
 	{
-	  if (DECL_IGNORED_P (fde->decl))
+	  if (fde->ignored_debug)
 	    continue;
 	  if (!fde->in_std_section)
             add_ranges_by_labels (main_comp_unit_die, fde->dw_fde_begin,
@@ -32331,9 +32472,12 @@  dwarf2out_c_finalize (void)
   skeleton_debug_str_hash = NULL;
   dw2_string_counter = 0;
   have_multiple_function_sections = false;
-  text_section_used = false;
-  cold_text_section_used = false;
+  in_text_section_p = false;
   cold_text_section = NULL;
+  last_text_label = NULL;
+  last_cold_label = NULL;
+  switch_text_ranges = NULL;
+  switch_cold_ranges = NULL;
   current_unit_personality = NULL;
 
   early_dwarf = false;
diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
index d659a96..7a998dc 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -108,6 +108,8 @@  struct GTY(()) dw_fde_node {
   /* True iff dw_fde_second_begin label is in text_section or
      cold_text_section.  */
   unsigned second_in_std_section : 1;
+  /* True iff this function is to be ignored by debugger.  */
+  unsigned ignored_debug : 1;
 };
 
 
diff --git a/gcc/final.c b/gcc/final.c
index b037e07..e5daa26 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1737,6 +1737,9 @@  final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen,
   if (!dwarf2_debug_info_emitted_p (current_function_decl))
     dwarf2out_begin_prologue (0, 0, NULL);
 
+  if (DECL_IGNORED_P (current_function_decl) && last_linenum && last_filename)
+    debug_hooks->set_ignored_loc (last_linenum, last_columnnum, last_filename);
+
 #ifdef LEAF_REG_REMAP
   if (crtl->uses_only_leaf_regs)
     leaf_renumber_regs (first);
@@ -2218,6 +2221,7 @@  final_scan_insn_1 (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 
 	  in_cold_section_p = !in_cold_section_p;
 
+	  gcc_checking_assert (in_cold_section_p);
 	  if (in_cold_section_p)
 	    cold_function_name
 	      = clone_function_name (current_function_decl, "cold");
@@ -2231,6 +2235,10 @@  final_scan_insn_1 (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 	    }
 	  else if (!DECL_IGNORED_P (current_function_decl))
 	    debug_hooks->switch_text_section ();
+	  if (DECL_IGNORED_P (current_function_decl) && last_linenum
+	      && last_filename)
+	    debug_hooks->set_ignored_loc (last_linenum, last_columnnum,
+					  last_filename);
 
 	  switch_to_section (current_function_section ());
 	  targetm.asm_out.function_switched_text_sections (asm_out_file,
diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c
index 4d11692..1b09f0d 100644
--- a/gcc/ggc-page.c
+++ b/gcc/ggc-page.c
@@ -1518,6 +1518,12 @@  gt_ggc_mx (const char *& x)
 }
 
 void
+gt_ggc_mx (char *& x)
+{
+  gt_ggc_m_S (x);
+}
+
+void
 gt_ggc_mx (unsigned char *& x)
 {
   gt_ggc_m_S (x);
diff --git a/gcc/stringpool.c b/gcc/stringpool.c
index e4d79b0..2f21466 100644
--- a/gcc/stringpool.c
+++ b/gcc/stringpool.c
@@ -206,6 +206,12 @@  gt_pch_nx (const char *& x)
 }
 
 void
+gt_pch_nx (char *& x)
+{
+  gt_pch_n_S (x);
+}
+
+void
 gt_pch_nx (unsigned char *& x)
 {
   gt_pch_n_S (x);
diff --git a/gcc/vmsdbgout.c b/gcc/vmsdbgout.c
index a764000..cf48b93 100644
--- a/gcc/vmsdbgout.c
+++ b/gcc/vmsdbgout.c
@@ -188,6 +188,7 @@  const struct gcc_debug_hooks vmsdbg_debug_hooks
    vmsdbgout_end_block,
    vmsdbgout_ignore_block,
    vmsdbgout_source_line,
+   debug_nothing_int_int_charstar, /* set_ignored_loc */
    vmsdbgout_begin_prologue,
    vmsdbgout_end_prologue,
    vmsdbgout_begin_epilogue,
-- 
1.9.1